Rewrite TLS support
The new implementation allows for per-server certificates. * libmu_auth/Makefile.am: Build tls support depending on the value of MU_COND_GNUTLS. * libmu_auth/notls.c: New file. * libmu_auth/tls.c: Rewrite. * libmu_auth/tlsiostr.c: New file. * libmu_auth/tlsvar.c: New file. * libmu_auth/tlsconf.c: New file. * include/mailutils/sys/tls-stream.h (_mu_tls_stream): New members: session_type, conf, cred. (mu_tls_io_stream_create): New proto. * include/mailutils/tls.h (mu_tls_module_config): Remove definition. (mu_tls_config): New structure. (mu_tls_server_stream_create): Remove proto. (mu_tls_cert_file_checks) (mu_tls_key_file_checksr) (mu_tls_ca_file_checks): New globals (MU_TLS_CERT_FILE_CHECKS) (MU_TLS_KEY_FILE_CHECKS) (MU_TLS_CA_FILE_CHECKS): New defines. (mu_tls_stream_create): New proto. (mu_tls_config_status): New constants. (mu_tls_check_config): Remove. (mu_tls_config_check): New function. * include/mailutils/server.h (mu_m_server_preflight_fp): New typedef. (mu_m_server_set_preflight): New proto. * libmailutils/diag/debcat (tls): New category. * libmailutils/server/ipsrv.c (mu_ip_server_get_data): New function. * libmailutils/server/msrv.c (_mu_m_server) <preflight>: New method. (mu_m_server_set_preflight): New function. (mu_m_server_destroy): Destroy the srvlist. (open_connection): New function. (mu_m_server_run): Remove from srvlist only those servers that failed to open. Run preflight check, if registered. * include/mailutils/cfg.h (mu_cfg_section): New member: data. * libmailutils/cfg/driver.c (dup_container): Copy the "data" pointer. (mu_cfg_section_add_params): Preserve original pointer and offset when necessary. * libmailutils/cfg/parser.y (_scan_tree_helper): Use the section data pointer (if set) as data target. * configure.ac (MU_COND_GNUTLS): New conditional. * imap4d/commands.c: Remove #ifdef WITH_TLS preprocessor conditional. * imap4d/imap4d.c (tls_mode): Remove variable. (imap4d_srv_config): Move definition to the header file. Remove #ifdef WITH_TLS preprocessor conditionals. Rename the tls configuration statement to tls-mode. Add new subsection .server.tls; Remove the legacy tls-required configuration statement. (imap4d_mainloop): Change signature: take a pointer to the struct imap4d_srv_config as the 3rd argument, Use the cfg->tls_mode member to decide on TLS state. (main): Call mu_tls_cfg_init. Install server preflight checker. * imap4d/imap4d.h: Remove #ifdef WITH_TLS preprocessor conditionals. (imap4d_srv_config): Moved from imap4d.c New member: tls_conf (imap4d_session): New member: tls_conf (global_tls_conf): New global. (io_setio, imap4d_init_tls_server): Change prototypes. * imap4d/io.c (io_setio): Change signature: take a pointer to the struct mu_tls_config as the 3rd argument. Rewrite TLS support. (imap4d_init_tls_server): Take a pointer to the struct mu_tls_config. * imap4d/starttls.c (tls_available, tls_done): Remove globals. (global_tls_conf): New global. (imap4d_starttls): Keep TLS state in the session. (tls_encryption_on): Likewise. (starttls_init): Rewrite as a mserver preflight check function. * pop3d/capa.c: Remove #ifdef WITH_TLS preprocessor conditional. (capa_stls): Rewrite. * pop3d/cmd.c (global_tls_conf): New global. (stls_preflight): New function. (pop3d_error_string): Rewrite using char ** array. * pop3d/extra.c (pop3d_setio): Take a pointer to struct mu_tls_config as the 3rd argument. Decide on TLS using it. (pop3d_init_tls_server): Take a pointer to struct mu_tls_config. * pop3d/pop3d.c: Rename the tls configuration statement to tls-mode. Add new subsection .server.tls; Remove the legacy tls-required configuration statement. (pop3d_mainloop) Take a pointer to struct mu_tls_config as the 3rd argument. Decide on TLS using it. (main): Call mu_tls_cfg_init. Install server preflight check. * pop3d/pop3d.h (pop3d_session): New member tls_conf. (pop3d_srv_config): New definition. (global_tls_conf): New extern. * pop3d/stls.c: Rewrite TLS support. * NEWS: Document new features. * configure.ac: Version 3.2.90. * doc/texinfo/programs.texi: Update.
Showing
29 changed files
with
1426 additions
and
930 deletions
1 | GNU mailutils NEWS -- history of user-visible changes. 2017-03-11 | 1 | GNU mailutils NEWS -- history of user-visible changes. 2017-03-18 |
2 | Copyright (C) 2002-2017 Free Software Foundation, Inc. | 2 | Copyright (C) 2002-2017 Free Software Foundation, Inc. |
3 | See the end of file for copying conditions. | 3 | See the end of file for copying conditions. |
4 | 4 | ||
5 | Please send mailutils bug reports to <bug-mailutils@gnu.org>. | 5 | Please send mailutils bug reports to <bug-mailutils@gnu.org>. |
6 | 6 | ||
7 | 7 | ||
8 | Version 3.2.90 (Git) | ||
9 | |||
10 | * TLS configuration | ||
11 | |||
12 | Note the following changes to the TLS configuration: | ||
13 | |||
14 | ** global tls section | ||
15 | |||
16 | The following statements have been renamed: | ||
17 | |||
18 | ssl-cafile renamed to ssl-ca-file | ||
19 | ssl-cert renamed to ssl-certificate-file | ||
20 | ssl-key renamed to ssl-key-file | ||
21 | |||
22 | The following statements have been removed: | ||
23 | |||
24 | enable | ||
25 | key-file-safety-checks | ||
26 | cert-file-safety-checks | ||
27 | ca-file-safety-checks | ||
28 | |||
29 | The functionality of the latter three is now moved to the | ||
30 | tls-file-checks section. | ||
31 | |||
32 | Example of a valid global tls section: | ||
33 | |||
34 | tls { | ||
35 | ssl-certificate-file /etc/ssl/cert/imap.pem; | ||
36 | ssl-key-file /etc/ssl/private/imap.key; | ||
37 | } | ||
38 | |||
39 | ** global tls-file-checks statement | ||
40 | |||
41 | The tls-file-checks statement configures safety checks for SSL | ||
42 | certificate and key files. It is a global section. Its syntax is | ||
43 | as follows: | ||
44 | |||
45 | tls-file-checks { | ||
46 | key-file <arg: list>; | ||
47 | cert-file <arg: list>; | ||
48 | ca-file <arg: list>; | ||
49 | } | ||
50 | |||
51 | The <arg> list is a list or sequence of check names optionally | ||
52 | prefixed with '+' to enable or '-' to disable the corresponding check. | ||
53 | Valid check names are the same as in previous versions. | ||
54 | |||
55 | Use this statement instead of the deprecated cert-file-safety-checks, | ||
56 | key-file-safety-checks, and ca-file-safety-checks. | ||
57 | |||
58 | * Per-server TLS support | ||
59 | |||
60 | It is now possible to configure per-server SSL certificates in POP3 | ||
61 | and IMAP4 servers. To do so, place a "tls" subsection within the | ||
62 | corresponding "server" section. The syntax of the "tls" subsection | ||
63 | is the same as for the global section described above, e.g.: | ||
64 | |||
65 | server imap.example.com:143 { | ||
66 | tls-mode required; | ||
67 | tls { | ||
68 | ssl-certificate-file /etc/ssl/cert/imap.pem; | ||
69 | ssl-key-file /etc/ssl/private/imap.key; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | If the "tls" section is absent, but "tls-mode" is specified and it's | ||
74 | value is anything but "no", the settings from the global "tls" section | ||
75 | will be used. Im this case, it is an error if the global "tls" | ||
76 | section is not defined. | ||
77 | |||
78 | |||
8 | Version 3.2 - 2017-03-11 | 79 | Version 3.2 - 2017-03-11 |
9 | 80 | ||
10 | * configuration syntax | 81 | * configuration syntax | ... | ... |
... | @@ -16,7 +16,7 @@ dnl You should have received a copy of the GNU General Public License along | ... | @@ -16,7 +16,7 @@ dnl You should have received a copy of the GNU General Public License along |
16 | dnl with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. | 16 | dnl with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. |
17 | 17 | ||
18 | AC_PREREQ(2.63) | 18 | AC_PREREQ(2.63) |
19 | AC_INIT([GNU Mailutils], [3.2], [bug-mailutils@gnu.org], [mailutils], | 19 | AC_INIT([GNU Mailutils], [3.2.90], [bug-mailutils@gnu.org], [mailutils], |
20 | [http://mailutils.org]) | 20 | [http://mailutils.org]) |
21 | AC_CONFIG_SRCDIR([libmailutils/mailbox/mailbox.c]) | 21 | AC_CONFIG_SRCDIR([libmailutils/mailbox/mailbox.c]) |
22 | AC_CONFIG_AUX_DIR([build-aux]) | 22 | AC_CONFIG_AUX_DIR([build-aux]) |
... | @@ -306,6 +306,7 @@ MU_CHECK_GNUTLS([1.2.1],[ | ... | @@ -306,6 +306,7 @@ MU_CHECK_GNUTLS([1.2.1],[ |
306 | ],[ | 306 | ],[ |
307 | status_gnutls=no | 307 | status_gnutls=no |
308 | ]) | 308 | ]) |
309 | AM_CONDITIONAL([MU_COND_GNUTLS], [test "$status_gnutls" = yes]) | ||
309 | 310 | ||
310 | AC_SUBST(SITE_MAIL_RC) | 311 | AC_SUBST(SITE_MAIL_RC) |
311 | AC_ARG_WITH([mail-rc], | 312 | AC_ARG_WITH([mail-rc], | ... | ... |
... | @@ -417,6 +417,7 @@ configuration files. | ... | @@ -417,6 +417,7 @@ configuration files. |
417 | * sql statement:: | 417 | * sql statement:: |
418 | * ldap statement:: | 418 | * ldap statement:: |
419 | * tls statement:: | 419 | * tls statement:: |
420 | * tls-file-checks statement:: | ||
420 | * gsasl statement:: | 421 | * gsasl statement:: |
421 | @end menu | 422 | @end menu |
422 | 423 | ||
... | @@ -1700,8 +1701,19 @@ server @var{ipaddr}[:@var{port}] @{ | ... | @@ -1700,8 +1701,19 @@ server @var{ipaddr}[:@var{port}] @{ |
1700 | backlog <number: callback>; | 1701 | backlog <number: callback>; |
1701 | 1702 | ||
1702 | # @r{Kind of TLS encryption to use for this server.} | 1703 | # @r{Kind of TLS encryption to use for this server.} |
1703 | tls @samp{no}|@samp{ondemand}|@samp{required}|@samp{connection}; | 1704 | tls-mode @samp{no}|@samp{ondemand}|@samp{required}|@samp{connection}; |
1704 | 1705 | ||
1706 | tls @{ | ||
1707 | # @r{Specify SSL certificate file.} | ||
1708 | ssl-certificate-file @var{string}; | ||
1709 | # @r{Specify SSL certificate key file.} | ||
1710 | ssl-key-file @var{file}; | ||
1711 | # @r{Specify trusted CAs file.} | ||
1712 | ssl-ca-file @var{file}; | ||
1713 | # @r{Set the priorities to use on the ciphers, methods, etc.} | ||
1714 | ssl-priorities @var{string}; | ||
1715 | @} | ||
1716 | |||
1705 | # @r{Set server specific ACLs.} | 1717 | # @r{Set server specific ACLs.} |
1706 | acl @{ /* @xref{ACL Statement}. */ @}; | 1718 | acl @{ /* @xref{ACL Statement}. */ @}; |
1707 | @} | 1719 | @} |
... | @@ -1756,7 +1768,7 @@ settings (@pxref{General Server Configuration, timeout}). | ... | @@ -1756,7 +1768,7 @@ settings (@pxref{General Server Configuration, timeout}). |
1756 | Configures the size of the queue of pending connections | 1768 | Configures the size of the queue of pending connections |
1757 | @end deffn | 1769 | @end deffn |
1758 | 1770 | ||
1759 | @deffn {Configuration} tls @var{mode}; | 1771 | @deffn {Configuration} tls-mode @var{mode}; |
1760 | Configure the use of TLS encryption. The @var{mode} argument is one | 1772 | Configure the use of TLS encryption. The @var{mode} argument is one |
1761 | of the following: | 1773 | of the following: |
1762 | 1774 | ||
... | @@ -1781,6 +1793,20 @@ TLS is always forced when the connection is established. For | ... | @@ -1781,6 +1793,20 @@ TLS is always forced when the connection is established. For |
1781 | @end table | 1793 | @end table |
1782 | @end deffn | 1794 | @end deffn |
1783 | 1795 | ||
1796 | @deffn {Configuration} tls @{ ... @} | ||
1797 | The @code{tls} statement configures SSL certificate and key files, as | ||
1798 | well as other SSL settings for use in this server. It is used when | ||
1799 | @code{tls-mode} is set to any of the following values: | ||
1800 | @code{ondemand}, @code{required}, @code{connection}. | ||
1801 | |||
1802 | If @code{tls-mode} is set to any of the values above and @code{tls} | ||
1803 | section is absent, settings from the global @code{tls} section will | ||
1804 | be used. In this case, it is an error if the global @code{tls} | ||
1805 | section is not defined. | ||
1806 | |||
1807 | @xref{tls statement}, for a discussion of its syntax. | ||
1808 | @end deffn | ||
1809 | |||
1784 | @deffn {Configuration} acl | 1810 | @deffn {Configuration} acl |
1785 | This statement defines a per-server Access Control List. Its syntax | 1811 | This statement defines a per-server Access Control List. Its syntax |
1786 | is as described in @ref{ACL Statement}. Per-server ACLs complement, | 1812 | is as described in @ref{ACL Statement}. Per-server ACLs complement, |
... | @@ -2483,39 +2509,32 @@ default filter is: | ... | @@ -2483,39 +2509,32 @@ default filter is: |
2483 | @subheading Syntax | 2509 | @subheading Syntax |
2484 | @example | 2510 | @example |
2485 | tls @{ | 2511 | tls @{ |
2486 | # @r{Enable TLS support.} | ||
2487 | enable @var{bool}; | ||
2488 | # @r{Specify SSL certificate file.} | 2512 | # @r{Specify SSL certificate file.} |
2489 | ssl-cert @var{string}; | 2513 | ssl-certificate-file @var{string}; |
2490 | # @r{Specify SSL certificate key file.} | 2514 | # @r{Specify SSL certificate key file.} |
2491 | ssl-key @var{file}; | 2515 | ssl-key-file @var{file}; |
2492 | # @r{Specify trusted CAs file.} | 2516 | # @r{Specify trusted CAs file.} |
2493 | ssl-cafile @var{file}; | 2517 | ssl-ca-file @var{file}; |
2494 | # @r{Set the priorities to use on the ciphers, methods, etc.} | 2518 | # @r{Set the priorities to use on the ciphers, methods, etc.} |
2495 | ssl-priorities @var{string}; | 2519 | ssl-priorities @var{string}; |
2496 | # @r{Configure safety checks for SSL key file.} | ||
2497 | key-file-safety-checks @var{list}; | ||
2498 | # @r{Configure safety checks for SSL certificate.} | ||
2499 | cert-file-safety-checks @var{list}; | ||
2500 | # @r{Configure safety checks for SSL CA file.} | ||
2501 | ca-file-safety-checks @var{list}; | ||
2502 | @} | 2520 | @} |
2503 | @end example | 2521 | @end example |
2504 | @subheading Description | 2522 | @subheading Description |
2505 | 2523 | ||
2506 | @deffn {Configuration} enable @var{bool} | 2524 | The @samp{tls} statement configures TLS parameters to be used by |
2507 | Enable TLS support. If absent, @samp{enable On} is assumed. | 2525 | servers. It can appear both in the global scope and in server |
2508 | @end deffn | 2526 | scope. Global tls settings are applied for servers that are declared |
2527 | as supporting TLS encryption, but lack the @samp{tls} substatement. | ||
2509 | 2528 | ||
2510 | @deffn {Configuration} ssl-cert @var{string} | 2529 | @deffn {Configuration} ssl-certificate-file @var{string} |
2511 | Specify SSL certificate file. | 2530 | Specify SSL certificate file. |
2512 | @end deffn | 2531 | @end deffn |
2513 | 2532 | ||
2514 | @deffn {Configuration} ssl-key @var{file} | 2533 | @deffn {Configuration} ssl-key-file @var{file} |
2515 | Specify SSL certificate key file. | 2534 | Specify SSL certificate key file. |
2516 | @end deffn | 2535 | @end deffn |
2517 | 2536 | ||
2518 | @deffn {Configuration} ssl-cafile @var{file} | 2537 | @deffn {Configuration} ssl-ca-file @var{file} |
2519 | Specify the trusted certificate authorities file. | 2538 | Specify the trusted certificate authorities file. |
2520 | @end deffn | 2539 | @end deffn |
2521 | 2540 | ||
... | @@ -2524,7 +2543,27 @@ Set the priorities to use on the ciphers, key exchange methods, MACs | ... | @@ -2524,7 +2543,27 @@ Set the priorities to use on the ciphers, key exchange methods, MACs |
2524 | and compression methods. | 2543 | and compression methods. |
2525 | @end deffn | 2544 | @end deffn |
2526 | 2545 | ||
2527 | @deffn {Configuration} key-file-safety-checks @var{list} | 2546 | @node tls-file-checks statement |
2547 | @subsection The @code{tls-file-checks} Statement | ||
2548 | @kwindex tls-file-checks | ||
2549 | @subheading Syntax | ||
2550 | @example | ||
2551 | tls-file-checks @{ | ||
2552 | # @r{Configure safety checks for SSL key file.} | ||
2553 | key-file @var{list}; | ||
2554 | # @r{Configure safety checks for SSL certificate.} | ||
2555 | cert-file @var{list}; | ||
2556 | # @r{Configure safety checks for SSL CA file.} | ||
2557 | ca-file @var{list}; | ||
2558 | @} | ||
2559 | @end example | ||
2560 | |||
2561 | @subheading Description | ||
2562 | |||
2563 | This section configures security checks applied to the particular SSL | ||
2564 | configuration files in order to decide whether it is safe to use them. | ||
2565 | |||
2566 | @deffn {Configuration} key-file @var{list} | ||
2528 | Configure safety checks for SSL key file. Elements of the @var{list} are | 2567 | Configure safety checks for SSL key file. Elements of the @var{list} are |
2529 | names of individual checks, optionally prefixed with @samp{+} to enable or | 2568 | names of individual checks, optionally prefixed with @samp{+} to enable or |
2530 | @samp{-} to disable the corresponding check. Valid check names are: | 2569 | @samp{-} to disable the corresponding check. Valid check names are: |
... | @@ -2551,16 +2590,17 @@ Forbid files in world writable directories, | ... | @@ -2551,16 +2590,17 @@ Forbid files in world writable directories, |
2551 | @end table | 2590 | @end table |
2552 | @end deffn | 2591 | @end deffn |
2553 | 2592 | ||
2554 | @deffn {Configuration} cert-file-safety-checks @var{list} | 2593 | @deffn {Configuration} cert-file @var{list} |
2555 | Configure safety checks for SSL certificate. See | 2594 | Configure safety checks for SSL certificate. See |
2556 | @code{key-file-safety-checks} for a description of @var{list}. | 2595 | @code{key-file} for a description of @var{list}. |
2557 | @end deffn | 2596 | @end deffn |
2558 | 2597 | ||
2559 | @deffn {Configuration} ca-file-safety-checks @var{list} | 2598 | @deffn {Configuration} ca-file @var{list} |
2560 | Configure safety checks for SSL CA file. See | 2599 | Configure safety checks for SSL CA file. See |
2561 | @code{key-file-safety-checks} for a description of @var{list}. | 2600 | @code{key-file} for a description of @var{list}. |
2562 | @end deffn | 2601 | @end deffn |
2563 | 2602 | ||
2603 | |||
2564 | @node gsasl statement | 2604 | @node gsasl statement |
2565 | @subsection The @code{gsasl} Statement | 2605 | @subsection The @code{gsasl} Statement |
2566 | @anchor{GSASL Statement} | 2606 | @anchor{GSASL Statement} |
... | @@ -7494,6 +7534,7 @@ The following configuration file statements affect the behavior of | ... | @@ -7494,6 +7534,7 @@ The following configuration file statements affect the behavior of |
7494 | @headitem Statement @tab Reference | 7534 | @headitem Statement @tab Reference |
7495 | @item debug @tab @xref{debug statement}. | 7535 | @item debug @tab @xref{debug statement}. |
7496 | @item tls @tab @xref{tls statement}. | 7536 | @item tls @tab @xref{tls statement}. |
7537 | @item tls-file-checks @tab @xref{tls-file-checks statement}. | ||
7497 | @item mailbox @tab @xref{mailbox statement}. | 7538 | @item mailbox @tab @xref{mailbox statement}. |
7498 | @item locking @tab @xref{locking statement}. | 7539 | @item locking @tab @xref{locking statement}. |
7499 | @item logging @tab @xref{logging statement}. | 7540 | @item logging @tab @xref{logging statement}. |
... | @@ -7804,6 +7845,7 @@ configuration statements: | ... | @@ -7804,6 +7845,7 @@ configuration statements: |
7804 | @headitem Statement @tab Reference | 7845 | @headitem Statement @tab Reference |
7805 | @item debug @tab @xref{debug statement}. | 7846 | @item debug @tab @xref{debug statement}. |
7806 | @item tls @tab @xref{tls statement}. | 7847 | @item tls @tab @xref{tls statement}. |
7848 | @item tls-file-checks @tab @xref{tls-file-checks statement}. | ||
7807 | @item mailbox @tab @xref{mailbox statement}. | 7849 | @item mailbox @tab @xref{mailbox statement}. |
7808 | @item locking @tab @xref{locking statement}. | 7850 | @item locking @tab @xref{locking statement}. |
7809 | @item logging @tab @xref{logging statement}. | 7851 | @item logging @tab @xref{logging statement}. | ... | ... |
... | @@ -47,8 +47,6 @@ struct imap4d_command imap4d_command_table [] = | ... | @@ -47,8 +47,6 @@ struct imap4d_command imap4d_command_table [] = |
47 | { "NAMESPACE", imap4d_namespace, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL }, | 47 | { "NAMESPACE", imap4d_namespace, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL }, |
48 | { "ID", imap4d_id, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL }, | 48 | { "ID", imap4d_id, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL }, |
49 | { "IDLE", imap4d_idle, STATE_SEL, STATE_NONE, STATE_NONE, NULL }, | 49 | { "IDLE", imap4d_idle, STATE_SEL, STATE_NONE, STATE_NONE, NULL }, |
50 | #ifdef WITH_TLS | ||
51 | { "STARTTLS", imap4d_starttls, STATE_NONAUTH, STATE_NONE, STATE_NONE, NULL }, | 50 | { "STARTTLS", imap4d_starttls, STATE_NONAUTH, STATE_NONE, STATE_NONE, NULL }, |
52 | #endif /* WITH_TLS */ | ||
53 | { NULL, 0, 0, 0, 0, NULL } | 51 | { NULL, 0, 0, 0, 0, NULL } |
54 | }; | 52 | }; | ... | ... |
... | @@ -30,7 +30,6 @@ char *real_homedir; /* Homedir as returned by user database */ | ... | @@ -30,7 +30,6 @@ char *real_homedir; /* Homedir as returned by user database */ |
30 | int state = STATE_NONAUTH; /* Current IMAP4 state */ | 30 | int state = STATE_NONAUTH; /* Current IMAP4 state */ |
31 | struct mu_auth_data *auth_data; | 31 | struct mu_auth_data *auth_data; |
32 | 32 | ||
33 | enum tls_mode tls_mode; | ||
34 | int login_disabled; /* Disable LOGIN command */ | 33 | int login_disabled; /* Disable LOGIN command */ |
35 | int create_home_dir; /* Create home directory if it does not | 34 | int create_home_dir; /* Create home directory if it does not |
36 | exist */ | 35 | exist */ |
... | @@ -258,13 +257,6 @@ cb_group (void *data, mu_config_value_t *arg) | ... | @@ -258,13 +257,6 @@ cb_group (void *data, mu_config_value_t *arg) |
258 | } | 257 | } |
259 | 258 | ||
260 | 259 | ||
261 | struct imap4d_srv_config | ||
262 | { | ||
263 | struct mu_srv_config m_cfg; | ||
264 | enum tls_mode tls_mode; | ||
265 | }; | ||
266 | |||
267 | #ifdef WITH_TLS | ||
268 | static int | 260 | static int |
269 | cb_tls (void *data, mu_config_value_t *val) | 261 | cb_tls (void *data, mu_config_value_t *val) |
270 | { | 262 | { |
... | @@ -293,33 +285,6 @@ cb_tls (void *data, mu_config_value_t *val) | ... | @@ -293,33 +285,6 @@ cb_tls (void *data, mu_config_value_t *val) |
293 | mu_error (_("not a valid tls keyword: %s"), val->v.string); | 285 | mu_error (_("not a valid tls keyword: %s"), val->v.string); |
294 | return 0; | 286 | return 0; |
295 | } | 287 | } |
296 | #endif | ||
297 | |||
298 | #ifdef WITH_TLS | ||
299 | static int | ||
300 | cb_tls_required (void *data, mu_config_value_t *val) | ||
301 | { | ||
302 | int bv; | ||
303 | |||
304 | if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) | ||
305 | return 1; | ||
306 | if (mu_str_to_c (val->v.string, mu_c_bool, &bv, NULL)) | ||
307 | mu_error (_("Not a boolean value")); | ||
308 | else if (bv) | ||
309 | { | ||
310 | tls_mode = tls_required; | ||
311 | mu_diag_output (MU_DIAG_WARNING, | ||
312 | "the \"tls-required\" statement is deprecated, " | ||
313 | "use \"tls required\" instead"); | ||
314 | } | ||
315 | else | ||
316 | mu_diag_output (MU_DIAG_WARNING, | ||
317 | "the \"tls-required\" statement is deprecated, " | ||
318 | "use \"tls\" instead"); | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | #endif | ||
323 | 288 | ||
324 | static mu_list_t auth_deny_user_list, auth_allow_user_list; | 289 | static mu_list_t auth_deny_user_list, auth_allow_user_list; |
325 | static mu_list_t auth_deny_group_list, auth_allow_group_list; | 290 | static mu_list_t auth_deny_group_list, auth_allow_group_list; |
... | @@ -532,13 +497,13 @@ namespace_cfg_init (void) | ... | @@ -532,13 +497,13 @@ namespace_cfg_init (void) |
532 | } | 497 | } |
533 | 498 | ||
534 | static struct mu_cfg_param imap4d_srv_param[] = { | 499 | static struct mu_cfg_param imap4d_srv_param[] = { |
535 | #ifdef WITH_TLS | 500 | { "tls-mode", mu_cfg_callback, |
536 | { "tls", mu_cfg_callback, | ||
537 | NULL, mu_offsetof (struct imap4d_srv_config, tls_mode), cb_tls, | 501 | NULL, mu_offsetof (struct imap4d_srv_config, tls_mode), cb_tls, |
538 | N_("Kind of TLS encryption to use for this server"), | 502 | N_("Kind of TLS encryption to use for this server"), |
539 | /* TRANSLATORS: translate only arg:, the rest are keywords */ | 503 | /* TRANSLATORS: translate only arg:, the rest are keywords */ |
540 | N_("arg: false|true|ondemand|stls|requred|connection") }, | 504 | N_("arg: false|true|ondemand|stls|requred|connection") }, |
541 | #endif | 505 | { "tls", mu_cfg_section, |
506 | NULL, mu_offsetof (struct imap4d_srv_config, tls_conf) }, | ||
542 | { NULL } | 507 | { NULL } |
543 | }; | 508 | }; |
544 | 509 | ||
... | @@ -568,16 +533,7 @@ static struct mu_cfg_param imap4d_cfg_param[] = { | ... | @@ -568,16 +533,7 @@ static struct mu_cfg_param imap4d_cfg_param[] = { |
568 | { "retain-groups", mu_cfg_callback, &user_retain_groups, 0, cb_group, | 533 | { "retain-groups", mu_cfg_callback, &user_retain_groups, 0, cb_group, |
569 | N_("Retain these supplementary groups when switching to user privileges"), | 534 | N_("Retain these supplementary groups when switching to user privileges"), |
570 | N_("groups: list of string") }, | 535 | N_("groups: list of string") }, |
571 | #ifdef WITH_TLS | 536 | { "tls", mu_cfg_section, &global_tls_conf }, |
572 | { "tls", mu_cfg_callback, &tls_mode, 0, cb_tls, | ||
573 | N_("Kind of TLS encryption to use"), | ||
574 | /* TRANSLATORS: translate only arg:, the rest are keywords */ | ||
575 | N_("arg: false|true|ondemand|stls|requred|connection") }, | ||
576 | { "tls-required", mu_cfg_callback, &tls_mode, 0, cb_tls_required, | ||
577 | N_("Always require STLS before entering authentication phase.\n" | ||
578 | "Deprecated, use \"tls required\" instead."), | ||
579 | N_("arg: bool") }, | ||
580 | #endif | ||
581 | { "preauth", mu_cfg_callback, NULL, 0, cb_preauth, | 537 | { "preauth", mu_cfg_callback, NULL, 0, cb_preauth, |
582 | N_("Configure PREAUTH mode. <value> is one of:\n" | 538 | N_("Configure PREAUTH mode. <value> is one of:\n" |
583 | " prog:///<full-program-name: string>\n" | 539 | " prog:///<full-program-name: string>\n" |
... | @@ -836,7 +792,7 @@ imap4d_child_signal_setup (RETSIGTYPE (*handler) (int signo)) | ... | @@ -836,7 +792,7 @@ imap4d_child_signal_setup (RETSIGTYPE (*handler) (int signo)) |
836 | } | 792 | } |
837 | 793 | ||
838 | static int | 794 | static int |
839 | imap4d_mainloop (int ifd, int ofd, enum tls_mode tls) | 795 | imap4d_mainloop (int ifd, int ofd, struct imap4d_srv_config *cfg) |
840 | { | 796 | { |
841 | imap4d_tokbuf_t tokp; | 797 | imap4d_tokbuf_t tokp; |
842 | char *text; | 798 | char *text; |
... | @@ -877,33 +833,27 @@ imap4d_mainloop (int ifd, int ofd, enum tls_mode tls) | ... | @@ -877,33 +833,27 @@ imap4d_mainloop (int ifd, int ofd, enum tls_mode tls) |
877 | /* Set child-specific signal handlers */ | 833 | /* Set child-specific signal handlers */ |
878 | imap4d_child_signal_setup (imap4d_child_signal); | 834 | imap4d_child_signal_setup (imap4d_child_signal); |
879 | } | 835 | } |
880 | |||
881 | if (tls == tls_unspecified) | ||
882 | tls = tls_available ? tls_ondemand : tls_no; | ||
883 | else if (tls != tls_no && !tls_available) | ||
884 | { | ||
885 | mu_error (_("TLS is not configured, but requested in the " | ||
886 | "configuration")); | ||
887 | tls = tls_no; | ||
888 | } | ||
889 | 836 | ||
890 | switch (tls) | 837 | switch (cfg->tls_mode) |
891 | { | 838 | { |
892 | case tls_required: | 839 | case tls_required: |
893 | imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED); | 840 | imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED); |
841 | imap4d_capability_add (IMAP_CAPA_STARTTLS); | ||
894 | break; | 842 | break; |
895 | case tls_no: | 843 | |
896 | imap4d_capability_remove (IMAP_CAPA_STARTTLS); | 844 | case tls_ondemand: |
897 | tls_available = 0; | 845 | imap4d_capability_add (IMAP_CAPA_STARTTLS); |
898 | break; | 846 | break; |
847 | |||
899 | default: | 848 | default: |
900 | break; | 849 | break; |
901 | } | 850 | } |
902 | 851 | ||
903 | session.tls_mode = tls; | 852 | session.tls_mode = cfg->tls_mode; |
853 | session.tls_conf = &cfg->tls_conf; | ||
904 | 854 | ||
905 | io_setio (ifd, ofd, tls == tls_connection); | 855 | io_setio (ifd, ofd, cfg->tls_mode == tls_connection ? &cfg->tls_conf : NULL); |
906 | if (tls == tls_connection) | 856 | if (cfg->tls_mode == tls_connection) |
907 | tls_encryption_on (&session); | 857 | tls_encryption_on (&session); |
908 | 858 | ||
909 | if (imap4d_preauth_setup (ifd) == 0) | 859 | if (imap4d_preauth_setup (ifd) == 0) |
... | @@ -961,8 +911,7 @@ imap4d_connection (int fd, struct sockaddr *sa, int salen, | ... | @@ -961,8 +911,7 @@ imap4d_connection (int fd, struct sockaddr *sa, int salen, |
961 | else | 911 | else |
962 | rc = 1; | 912 | rc = 1; |
963 | 913 | ||
964 | imap4d_mainloop (fd, fd, | 914 | imap4d_mainloop (fd, fd, cfg); |
965 | cfg->tls_mode == tls_unspecified ? tls_mode : cfg->tls_mode); | ||
966 | 915 | ||
967 | if (rc == 0) | 916 | if (rc == 0) |
968 | clr_strerr_flt (); | 917 | clr_strerr_flt (); |
... | @@ -1040,8 +989,9 @@ main (int argc, char **argv) | ... | @@ -1040,8 +989,9 @@ main (int argc, char **argv) |
1040 | mu_tcpwrapper_cfg_init (); | 989 | mu_tcpwrapper_cfg_init (); |
1041 | manlock_cfg_init (); | 990 | manlock_cfg_init (); |
1042 | mu_acl_cfg_init (); | 991 | mu_acl_cfg_init (); |
992 | mu_tls_cfg_init (); | ||
1043 | namespace_cfg_init (); | 993 | namespace_cfg_init (); |
1044 | 994 | ||
1045 | mu_m_server_create (&server, program_version); | 995 | mu_m_server_create (&server, program_version); |
1046 | mu_m_server_set_config_size (server, sizeof (struct imap4d_srv_config)); | 996 | mu_m_server_set_config_size (server, sizeof (struct imap4d_srv_config)); |
1047 | mu_m_server_set_conn (server, imap4d_connection); | 997 | mu_m_server_set_conn (server, imap4d_connection); |
... | @@ -1141,9 +1091,7 @@ main (int argc, char **argv) | ... | @@ -1141,9 +1091,7 @@ main (int argc, char **argv) |
1141 | umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */ | 1091 | umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */ |
1142 | 1092 | ||
1143 | /* Check TLS environment, i.e. cert and key files */ | 1093 | /* Check TLS environment, i.e. cert and key files */ |
1144 | #ifdef WITH_TLS | 1094 | mu_m_server_set_preflight (server, starttls_init); |
1145 | starttls_init (); | ||
1146 | #endif /* WITH_TLS */ | ||
1147 | 1095 | ||
1148 | /* Actually run the daemon. */ | 1096 | /* Actually run the daemon. */ |
1149 | if (mu_m_server_mode (server) == MODE_DAEMON) | 1097 | if (mu_m_server_mode (server) == MODE_DAEMON) |
... | @@ -1155,9 +1103,12 @@ main (int argc, char **argv) | ... | @@ -1155,9 +1103,12 @@ main (int argc, char **argv) |
1155 | } | 1103 | } |
1156 | else | 1104 | else |
1157 | { | 1105 | { |
1106 | struct imap4d_srv_config cfg; | ||
1107 | memset (&cfg, 0, sizeof cfg); | ||
1108 | cfg.tls_mode = tls_no; | ||
1158 | /* Make sure we are in the root directory. */ | 1109 | /* Make sure we are in the root directory. */ |
1159 | chdir ("/"); | 1110 | chdir ("/"); |
1160 | status = imap4d_mainloop (MU_STDIN_FD, MU_STDOUT_FD, tls_mode); | 1111 | status = imap4d_mainloop (MU_STDIN_FD, MU_STDOUT_FD, &cfg); |
1161 | } | 1112 | } |
1162 | 1113 | ||
1163 | if (status) | 1114 | if (status) | ... | ... |
... | @@ -193,6 +193,14 @@ enum tls_mode | ... | @@ -193,6 +193,14 @@ enum tls_mode |
193 | struct imap4d_session | 193 | struct imap4d_session |
194 | { | 194 | { |
195 | enum tls_mode tls_mode; | 195 | enum tls_mode tls_mode; |
196 | struct mu_tls_config *tls_conf; | ||
197 | }; | ||
198 | |||
199 | struct imap4d_srv_config | ||
200 | { | ||
201 | struct mu_srv_config m_cfg; | ||
202 | enum tls_mode tls_mode; | ||
203 | struct mu_tls_config tls_conf; | ||
196 | }; | 204 | }; |
197 | 205 | ||
198 | extern struct imap4d_command imap4d_command_table[]; | 206 | extern struct imap4d_command imap4d_command_table[]; |
... | @@ -217,7 +225,8 @@ extern mu_list_t imap4d_id_list; | ... | @@ -217,7 +225,8 @@ extern mu_list_t imap4d_id_list; |
217 | extern int imap4d_argc; | 225 | extern int imap4d_argc; |
218 | extern char **imap4d_argv; | 226 | extern char **imap4d_argv; |
219 | extern jmp_buf child_jmp; | 227 | extern jmp_buf child_jmp; |
220 | 228 | extern struct mu_tls_config global_tls_conf; | |
229 | |||
221 | extern int test_mode; | 230 | extern int test_mode; |
222 | extern int silent_expunge; | 231 | extern int silent_expunge; |
223 | 232 | ||
... | @@ -240,7 +249,7 @@ extern int io_stream_completion_response (mu_stream_t str, | ... | @@ -240,7 +249,7 @@ extern int io_stream_completion_response (mu_stream_t str, |
240 | const char *format, ...) | 249 | const char *format, ...) |
241 | MU_PRINTFLIKE(4,5); | 250 | MU_PRINTFLIKE(4,5); |
242 | void io_getline (char **pbuf, size_t *psize, size_t *pnbytes); | 251 | void io_getline (char **pbuf, size_t *psize, size_t *pnbytes); |
243 | void io_setio (int, int, int); | 252 | void io_setio (int, int, struct mu_tls_config *); |
244 | void io_flush (void); | 253 | void io_flush (void); |
245 | int io_wait_input (int); | 254 | int io_wait_input (int); |
246 | 255 | ||
... | @@ -333,14 +342,10 @@ extern int imap4d_select (struct imap4d_session *, | ... | @@ -333,14 +342,10 @@ extern int imap4d_select (struct imap4d_session *, |
333 | struct imap4d_command *, imap4d_tokbuf_t); | 342 | struct imap4d_command *, imap4d_tokbuf_t); |
334 | extern int imap4d_select0 (struct imap4d_command *, const char *, int); | 343 | extern int imap4d_select0 (struct imap4d_command *, const char *, int); |
335 | extern int imap4d_select_status (void); | 344 | extern int imap4d_select_status (void); |
336 | #ifdef WITH_TLS | ||
337 | extern int imap4d_starttls (struct imap4d_session *, | 345 | extern int imap4d_starttls (struct imap4d_session *, |
338 | struct imap4d_command *, imap4d_tokbuf_t); | 346 | struct imap4d_command *, imap4d_tokbuf_t); |
339 | extern void starttls_init (void); | 347 | int starttls_init (mu_m_server_t msrv); |
340 | void tls_encryption_on (struct imap4d_session *); | 348 | void tls_encryption_on (struct imap4d_session *); |
341 | #else | ||
342 | # define tls_encryption_on(s) | ||
343 | #endif /* WITH_TLS */ | ||
344 | extern int imap4d_status (struct imap4d_session *, | 349 | extern int imap4d_status (struct imap4d_session *, |
345 | struct imap4d_command *, imap4d_tokbuf_t); | 350 | struct imap4d_command *, imap4d_tokbuf_t); |
346 | extern int imap4d_store (struct imap4d_session *, | 351 | extern int imap4d_store (struct imap4d_session *, |
... | @@ -466,9 +471,7 @@ int util_trim_nl (char *s, size_t len); | ... | @@ -466,9 +471,7 @@ int util_trim_nl (char *s, size_t len); |
466 | 471 | ||
467 | int set_xscript_level (int xlev); | 472 | int set_xscript_level (int xlev); |
468 | 473 | ||
469 | #ifdef WITH_TLS | 474 | int imap4d_init_tls_server (struct mu_tls_config *); |
470 | int imap4d_init_tls_server (void); | ||
471 | #endif /* WITH_TLS */ | ||
472 | 475 | ||
473 | struct imap4d_auth | 476 | struct imap4d_auth |
474 | { | 477 | { | ... | ... |
... | @@ -50,7 +50,7 @@ log_cipher (mu_stream_t stream) | ... | @@ -50,7 +50,7 @@ log_cipher (mu_stream_t stream) |
50 | } | 50 | } |
51 | 51 | ||
52 | void | 52 | void |
53 | io_setio (int ifd, int ofd, int tls) | 53 | io_setio (int ifd, int ofd, struct mu_tls_config *tls_conf) |
54 | { | 54 | { |
55 | mu_stream_t str, istream, ostream; | 55 | mu_stream_t str, istream, ostream; |
56 | 56 | ||
... | @@ -68,10 +68,12 @@ io_setio (int ifd, int ofd, int tls) | ... | @@ -68,10 +68,12 @@ io_setio (int ifd, int ofd, int tls) |
68 | mu_stream_set_buffer (ostream, mu_buffer_line, 0); | 68 | mu_stream_set_buffer (ostream, mu_buffer_line, 0); |
69 | 69 | ||
70 | /* Combine the two streams into an I/O one. */ | 70 | /* Combine the two streams into an I/O one. */ |
71 | #ifdef WITH_TLS | 71 | if (tls_conf) |
72 | if (tls) | ||
73 | { | 72 | { |
74 | int rc = mu_tls_server_stream_create (&str, istream, ostream, 0); | 73 | int rc = mu_tls_stream_create (&str, istream, ostream, |
74 | tls_conf, | ||
75 | MU_TLS_SERVER, | ||
76 | 0); | ||
75 | if (rc) | 77 | if (rc) |
76 | { | 78 | { |
77 | mu_stream_unref (istream); | 79 | mu_stream_unref (istream); |
... | @@ -81,9 +83,7 @@ io_setio (int ifd, int ofd, int tls) | ... | @@ -81,9 +83,7 @@ io_setio (int ifd, int ofd, int tls) |
81 | } | 83 | } |
82 | log_cipher (str); | 84 | log_cipher (str); |
83 | } | 85 | } |
84 | else | 86 | else if (mu_iostream_create (&str, istream, ostream)) |
85 | #endif | ||
86 | if (mu_iostream_create (&str, istream, ostream)) | ||
87 | imap4d_bye (ERR_STREAM_CREATE); | 87 | imap4d_bye (ERR_STREAM_CREATE); |
88 | 88 | ||
89 | /* Convert all writes to CRLF form. | 89 | /* Convert all writes to CRLF form. |
... | @@ -120,9 +120,8 @@ io_setio (int ifd, int ofd, int tls) | ... | @@ -120,9 +120,8 @@ io_setio (int ifd, int ofd, int tls) |
120 | } | 120 | } |
121 | } | 121 | } |
122 | 122 | ||
123 | #ifdef WITH_TLS | ||
124 | int | 123 | int |
125 | imap4d_init_tls_server () | 124 | imap4d_init_tls_server (struct mu_tls_config *tls_conf) |
126 | { | 125 | { |
127 | mu_stream_t tlsstream, stream[2]; | 126 | mu_stream_t tlsstream, stream[2]; |
128 | int rc; | 127 | int rc; |
... | @@ -135,7 +134,12 @@ imap4d_init_tls_server () | ... | @@ -135,7 +134,12 @@ imap4d_init_tls_server () |
135 | return 1; | 134 | return 1; |
136 | } | 135 | } |
137 | 136 | ||
138 | rc = mu_tls_server_stream_create (&tlsstream, stream[0], stream[1], 0); | 137 | rc = mu_tls_stream_create (&tlsstream, stream[0], stream[1], |
138 | tls_conf, | ||
139 | MU_TLS_SERVER, | ||
140 | 0); | ||
141 | mu_stream_unref (stream[0]); | ||
142 | mu_stream_unref (stream[1]); | ||
139 | if (rc) | 143 | if (rc) |
140 | { | 144 | { |
141 | mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"), | 145 | mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"), |
... | @@ -145,8 +149,6 @@ imap4d_init_tls_server () | ... | @@ -145,8 +149,6 @@ imap4d_init_tls_server () |
145 | 149 | ||
146 | log_cipher (tlsstream); | 150 | log_cipher (tlsstream); |
147 | 151 | ||
148 | mu_stream_unref (stream[0]); | ||
149 | mu_stream_unref (stream[1]); | ||
150 | stream[0] = stream[1] = tlsstream; | 152 | stream[0] = stream[1] = tlsstream; |
151 | 153 | ||
152 | rc = mu_stream_ioctl (iostream, MU_IOCTL_SUBSTREAM, MU_IOCTL_OP_SET, stream); | 154 | rc = mu_stream_ioctl (iostream, MU_IOCTL_SUBSTREAM, MU_IOCTL_OP_SET, stream); |
... | @@ -158,11 +160,9 @@ imap4d_init_tls_server () | ... | @@ -158,11 +160,9 @@ imap4d_init_tls_server () |
158 | } | 160 | } |
159 | mu_stream_unref (stream[0]); | 161 | mu_stream_unref (stream[0]); |
160 | mu_stream_unref (stream[1]); | 162 | mu_stream_unref (stream[1]); |
161 | 163 | ||
162 | return 0; | 164 | return 0; |
163 | } | 165 | } |
164 | #endif | ||
165 | |||
166 | 166 | ||
167 | /* Status Code to String. */ | 167 | /* Status Code to String. */ |
168 | static const char * | 168 | static const char * | ... | ... |
... | @@ -17,11 +17,7 @@ | ... | @@ -17,11 +17,7 @@ |
17 | 17 | ||
18 | #include "imap4d.h" | 18 | #include "imap4d.h" |
19 | 19 | ||
20 | int tls_available; | 20 | struct mu_tls_config global_tls_conf; |
21 | |||
22 | #ifdef WITH_TLS | ||
23 | |||
24 | static int tls_done; | ||
25 | 21 | ||
26 | /* | 22 | /* |
27 | 6.2.1. STARTTLS Command | 23 | 6.2.1. STARTTLS Command |
... | @@ -39,7 +35,7 @@ imap4d_starttls (struct imap4d_session *session, | ... | @@ -39,7 +35,7 @@ imap4d_starttls (struct imap4d_session *session, |
39 | { | 35 | { |
40 | int status; | 36 | int status; |
41 | 37 | ||
42 | if (!tls_available || tls_done) | 38 | if (session->tls_mode == tls_no) |
43 | return io_completion_response (command, RESP_BAD, "Invalid command"); | 39 | return io_completion_response (command, RESP_BAD, "Invalid command"); |
44 | 40 | ||
45 | if (imap4d_tokbuf_argc (tok) != 2) | 41 | if (imap4d_tokbuf_argc (tok) != 2) |
... | @@ -48,7 +44,7 @@ imap4d_starttls (struct imap4d_session *session, | ... | @@ -48,7 +44,7 @@ imap4d_starttls (struct imap4d_session *session, |
48 | status = io_completion_response (command, RESP_OK, "Begin TLS negotiation"); | 44 | status = io_completion_response (command, RESP_OK, "Begin TLS negotiation"); |
49 | io_flush (); | 45 | io_flush (); |
50 | 46 | ||
51 | if (imap4d_init_tls_server () == 0) | 47 | if (imap4d_init_tls_server (session->tls_conf) == 0) |
52 | tls_encryption_on (session); | 48 | tls_encryption_on (session); |
53 | else | 49 | else |
54 | { | 50 | { |
... | @@ -63,24 +59,101 @@ imap4d_starttls (struct imap4d_session *session, | ... | @@ -63,24 +59,101 @@ imap4d_starttls (struct imap4d_session *session, |
63 | void | 59 | void |
64 | tls_encryption_on (struct imap4d_session *session) | 60 | tls_encryption_on (struct imap4d_session *session) |
65 | { | 61 | { |
66 | tls_done = 1; | 62 | session->tls_mode = tls_no; |
67 | imap4d_capability_remove (IMAP_CAPA_STARTTLS); | 63 | imap4d_capability_remove (IMAP_CAPA_STARTTLS); |
68 | 64 | ||
69 | login_disabled = 0; | 65 | login_disabled = 0; |
70 | imap4d_capability_remove (IMAP_CAPA_LOGINDISABLED); | 66 | imap4d_capability_remove (IMAP_CAPA_LOGINDISABLED); |
71 | 67 | ||
72 | session->tls_mode = tls_no; | ||
73 | imap4d_capability_remove (IMAP_CAPA_XTLSREQUIRED); | 68 | imap4d_capability_remove (IMAP_CAPA_XTLSREQUIRED); |
74 | } | 69 | } |
75 | 70 | ||
76 | void | 71 | int |
77 | starttls_init () | 72 | starttls_init (mu_m_server_t msrv) |
78 | { | 73 | { |
79 | tls_available = mu_check_tls_environment (); | 74 | mu_list_t srvlist; |
80 | if (tls_available) | 75 | mu_iterator_t itr; |
81 | imap4d_capability_add (IMAP_CAPA_STARTTLS); | 76 | int errors = 0; |
82 | } | 77 | int tls_ok = mu_init_tls_libs (); |
78 | int tls_requested = 0; | ||
79 | int global_conf_status = 0; | ||
80 | |||
81 | if (global_tls_conf.cert_file) | ||
82 | global_conf_status = mu_tls_config_check (&global_tls_conf, 1); | ||
83 | else | ||
84 | global_conf_status = MU_TLS_CONFIG_NULL; | ||
85 | |||
86 | mu_m_server_get_srvlist (msrv, &srvlist); | ||
87 | mu_list_get_iterator (srvlist, &itr); | ||
88 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) | ||
89 | { | ||
90 | mu_ip_server_t ipsrv; | ||
91 | struct imap4d_srv_config *cfg; | ||
92 | mu_iterator_current (itr, (void**) &ipsrv); | ||
93 | cfg = mu_ip_server_get_data (ipsrv); | ||
94 | switch (cfg->tls_mode) | ||
95 | { | ||
96 | case tls_unspecified: | ||
97 | if (cfg->tls_conf.cert_file) | ||
98 | { | ||
99 | cfg->tls_mode = tls_ondemand; | ||
100 | break; | ||
101 | } | ||
102 | else | ||
103 | cfg->tls_mode = tls_no; | ||
104 | /* fall through */ | ||
105 | case tls_no: | ||
106 | continue; | ||
107 | |||
108 | default: | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | switch (mu_tls_config_check (&cfg->tls_conf, 1)) | ||
113 | { | ||
114 | case MU_TLS_CONFIG_OK: | ||
115 | if (!cfg->tls_conf.cert_file) | ||
116 | { | ||
117 | mu_error (_("server %s: no certificate set"), | ||
118 | mu_ip_server_addrstr (ipsrv)); | ||
119 | errors = 1; | ||
120 | } | ||
121 | break; | ||
122 | |||
123 | case MU_TLS_CONFIG_NULL: | ||
124 | if (global_conf_status != MU_TLS_CONFIG_NULL) | ||
125 | { | ||
126 | cfg->tls_conf = global_tls_conf; | ||
127 | } | ||
128 | else | ||
129 | { | ||
130 | mu_error (_("server %s: no certificate set"), | ||
131 | mu_ip_server_addrstr (ipsrv)); | ||
132 | errors = 1; | ||
133 | } | ||
134 | break; | ||
135 | |||
136 | default: | ||
137 | mu_error (_("server %s: TLS configuration failed"), | ||
138 | mu_ip_server_addrstr (ipsrv)); | ||
139 | errors = 1; | ||
140 | } | ||
141 | |||
142 | tls_requested = 1; | ||
143 | } | ||
144 | mu_iterator_destroy (&itr); | ||
83 | 145 | ||
84 | #endif /* WITH_TLS */ | 146 | if (tls_requested && !tls_ok) |
147 | { | ||
148 | mu_error (_("TLS is not configured, but requested in the " | ||
149 | "configuration")); | ||
150 | errors = 1; | ||
151 | } | ||
152 | |||
153 | if (errors) | ||
154 | return 1; | ||
155 | |||
156 | return 0; | ||
157 | } | ||
85 | 158 | ||
86 | /* EOF */ | 159 | /* EOF */ | ... | ... |
... | @@ -180,13 +180,16 @@ typedef int (*mu_cfg_section_fp) (enum mu_cfg_section_stage stage, | ... | @@ -180,13 +180,16 @@ typedef int (*mu_cfg_section_fp) (enum mu_cfg_section_stage stage, |
180 | 180 | ||
181 | struct mu_cfg_section | 181 | struct mu_cfg_section |
182 | { | 182 | { |
183 | const char *ident; | 183 | const char *ident; /* Section identifier */ |
184 | char *label; | 184 | char *label; /* Label description */ |
185 | mu_cfg_section_fp parser; | 185 | mu_cfg_section_fp parser; /* Parser function */ |
186 | void *target; | 186 | void *data; /* Data pointer */ |
187 | size_t offset; | 187 | size_t offset; /* Offset within target (see below) */ |
188 | mu_list_t /* of mu_cfg_cont */ children; | 188 | mu_list_t /* of mu_cfg_cont */ children; |
189 | char *docstring; | 189 | char *docstring; /* Documentation string */ |
190 | void *target; /* Actual pointer to the data. It is | ||
191 | recomputed each time the section is | ||
192 | reduced. */ | ||
190 | }; | 193 | }; |
191 | 194 | ||
192 | enum mu_cfg_cont_type | 195 | enum mu_cfg_cont_type | ... | ... |
... | @@ -28,7 +28,7 @@ typedef int (*mu_conn_loop_fp) (int fd, void *conn_data, void *server_data); | ... | @@ -28,7 +28,7 @@ typedef int (*mu_conn_loop_fp) (int fd, void *conn_data, void *server_data); |
28 | typedef void (*mu_conn_free_fp) (void *conn_data, void *server_data); | 28 | typedef void (*mu_conn_free_fp) (void *conn_data, void *server_data); |
29 | typedef int (*mu_server_idle_fp) (void *server_data); | 29 | typedef int (*mu_server_idle_fp) (void *server_data); |
30 | typedef void (*mu_server_free_fp) (void *server_data); | 30 | typedef void (*mu_server_free_fp) (void *server_data); |
31 | 31 | ||
32 | #define MU_SERVER_SUCCESS 0 | 32 | #define MU_SERVER_SUCCESS 0 |
33 | #define MU_SERVER_CLOSE_CONN 1 | 33 | #define MU_SERVER_CLOSE_CONN 1 |
34 | #define MU_SERVER_SHUTDOWN 2 | 34 | #define MU_SERVER_SHUTDOWN 2 |
... | @@ -40,7 +40,8 @@ int mu_server_set_idle (mu_server_t srv, mu_server_idle_fp fp); | ... | @@ -40,7 +40,8 @@ int mu_server_set_idle (mu_server_t srv, mu_server_idle_fp fp); |
40 | int mu_server_set_data (mu_server_t srv, void *data, mu_server_free_fp fp); | 40 | int mu_server_set_data (mu_server_t srv, void *data, mu_server_free_fp fp); |
41 | int mu_server_add_connection (mu_server_t srv, | 41 | int mu_server_add_connection (mu_server_t srv, |
42 | int fd, void *data, | 42 | int fd, void *data, |
43 | mu_conn_loop_fp loop, mu_conn_free_fp free); | 43 | mu_conn_loop_fp loop, |
44 | mu_conn_free_fp free); | ||
44 | struct timeval; | 45 | struct timeval; |
45 | int mu_server_set_timeout (mu_server_t srv, struct timeval *to); | 46 | int mu_server_set_timeout (mu_server_t srv, struct timeval *to); |
46 | int mu_server_count (mu_server_t srv, size_t *pcount); | 47 | int mu_server_count (mu_server_t srv, size_t *pcount); |
... | @@ -100,6 +101,7 @@ typedef struct mu_m_server_connect_data mu_m_server_connect_data_t; | ... | @@ -100,6 +101,7 @@ typedef struct mu_m_server_connect_data mu_m_server_connect_data_t; |
100 | typedef int (*mu_m_server_handler_fp) (int fd, struct sockaddr *sa, int salen, | 101 | typedef int (*mu_m_server_handler_fp) (int fd, struct sockaddr *sa, int salen, |
101 | struct mu_srv_config *pconf, | 102 | struct mu_srv_config *pconf, |
102 | void *data); | 103 | void *data); |
104 | typedef int (*mu_m_server_preflight_fp) (mu_m_server_t); | ||
103 | 105 | ||
104 | void mu_m_server_create (mu_m_server_t *psrv, const char *ident); | 106 | void mu_m_server_create (mu_m_server_t *psrv, const char *ident); |
105 | void mu_m_server_destroy (mu_m_server_t *pmsrv); | 107 | void mu_m_server_destroy (mu_m_server_t *pmsrv); |
... | @@ -109,6 +111,7 @@ void mu_m_server_get_type (mu_m_server_t srv, int *ptype); | ... | @@ -109,6 +111,7 @@ void mu_m_server_get_type (mu_m_server_t srv, int *ptype); |
109 | void mu_m_server_set_conn (mu_m_server_t srv, mu_m_server_handler_fp f); | 111 | void mu_m_server_set_conn (mu_m_server_t srv, mu_m_server_handler_fp f); |
110 | void mu_m_server_set_prefork (mu_m_server_t srv, mu_m_server_handler_fp fun); | 112 | void mu_m_server_set_prefork (mu_m_server_t srv, mu_m_server_handler_fp fun); |
111 | void mu_m_server_set_data (mu_m_server_t srv, void *data); | 113 | void mu_m_server_set_data (mu_m_server_t srv, void *data); |
114 | void *mu_ip_server_get_data (mu_ip_server_t tcpsrv); | ||
112 | void mu_m_server_set_max_children (mu_m_server_t srv, size_t num); | 115 | void mu_m_server_set_max_children (mu_m_server_t srv, size_t num); |
113 | int mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile); | 116 | int mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile); |
114 | int mu_m_server_set_foreground (mu_m_server_t srv, int enable); | 117 | int mu_m_server_set_foreground (mu_m_server_t srv, int enable); |
... | @@ -119,6 +122,8 @@ void mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset); | ... | @@ -119,6 +122,8 @@ void mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset); |
119 | void mu_m_server_set_strexit (mu_m_server_t srv, const char *(*fun) (int)); | 122 | void mu_m_server_set_strexit (mu_m_server_t srv, const char *(*fun) (int)); |
120 | void mu_m_server_set_app_data_size (mu_m_server_t srv, size_t size); | 123 | void mu_m_server_set_app_data_size (mu_m_server_t srv, size_t size); |
121 | int mu_m_server_set_config_size (mu_m_server_t srv, size_t size); | 124 | int mu_m_server_set_config_size (mu_m_server_t srv, size_t size); |
125 | void mu_m_server_set_preflight (mu_m_server_t srv, | ||
126 | mu_m_server_preflight_fp fun); | ||
122 | 127 | ||
123 | struct mu_srv_config *mu_m_server_listen (mu_m_server_t msrv, | 128 | struct mu_srv_config *mu_m_server_listen (mu_m_server_t msrv, |
124 | struct mu_sockaddr *s, int type); | 129 | struct mu_sockaddr *s, int type); |
... | @@ -144,5 +149,4 @@ int mu_m_server_check_acl (mu_m_server_t msrv, struct sockaddr *s, int salen); | ... | @@ -144,5 +149,4 @@ int mu_m_server_check_acl (mu_m_server_t msrv, struct sockaddr *s, int salen); |
144 | struct mu_cfg_param; | 149 | struct mu_cfg_param; |
145 | void mu_m_server_cfg_init (mu_m_server_t msrv, struct mu_cfg_param *app_param); | 150 | void mu_m_server_cfg_init (mu_m_server_t msrv, struct mu_cfg_param *app_param); |
146 | 151 | ||
147 | |||
148 | #endif | 152 | #endif | ... | ... |
... | @@ -20,6 +20,7 @@ | ... | @@ -20,6 +20,7 @@ |
20 | # include <mailutils/types.h> | 20 | # include <mailutils/types.h> |
21 | # include <mailutils/stream.h> | 21 | # include <mailutils/stream.h> |
22 | # include <mailutils/sys/stream.h> | 22 | # include <mailutils/sys/stream.h> |
23 | # include <mailutils/tls.h> | ||
23 | 24 | ||
24 | enum _mu_tls_stream_state | 25 | enum _mu_tls_stream_state |
25 | { | 26 | { |
... | @@ -40,9 +41,16 @@ struct _mu_tls_stream | ... | @@ -40,9 +41,16 @@ struct _mu_tls_stream |
40 | { | 41 | { |
41 | struct _mu_stream stream; | 42 | struct _mu_stream stream; |
42 | enum _mu_tls_stream_state state; | 43 | enum _mu_tls_stream_state state; |
44 | int session_type; /* Either GNUTLS_CLIENT or GNUTLS_SERVER */ | ||
43 | gnutls_session_t session; | 45 | gnutls_session_t session; |
44 | int tls_err; | 46 | int tls_err; |
45 | mu_stream_t transport[2]; | 47 | mu_stream_t transport[2]; |
48 | struct mu_tls_config conf; | ||
49 | gnutls_certificate_credentials_t cred; | ||
46 | }; | 50 | }; |
47 | 51 | ||
52 | extern int mu_tls_io_stream_create (mu_stream_t *pstream, | ||
53 | mu_stream_t transport, int flags, | ||
54 | struct _mu_tls_stream *master); | ||
55 | |||
48 | #endif | 56 | #endif | ... | ... |
... | @@ -21,39 +21,67 @@ | ... | @@ -21,39 +21,67 @@ |
21 | 21 | ||
22 | #include <mailutils/types.h> | 22 | #include <mailutils/types.h> |
23 | #include <mailutils/cli.h> | 23 | #include <mailutils/cli.h> |
24 | #include <mailutils/util.h> | ||
24 | 25 | ||
25 | #ifdef __cplusplus | 26 | #ifdef __cplusplus |
26 | extern "C" { | 27 | extern "C" { |
27 | #endif | 28 | #endif |
28 | 29 | ||
29 | struct mu_tls_module_config | 30 | struct mu_tls_config |
30 | { | 31 | { |
31 | int enable; | 32 | char *cert_file; |
32 | 33 | char *key_file; | |
33 | char *ssl_cert; | 34 | char *ca_file; |
34 | int ssl_cert_safety_checks; | ||
35 | |||
36 | char *ssl_key; | ||
37 | int ssl_key_safety_checks; | ||
38 | |||
39 | char *ssl_cafile; | ||
40 | int ssl_cafile_safety_checks; | ||
41 | |||
42 | char *priorities; | 35 | char *priorities; |
43 | }; | 36 | }; |
44 | 37 | ||
45 | extern int mu_tls_server_stream_create (mu_stream_t *stream, | 38 | enum mu_tls_type |
46 | mu_stream_t strin, mu_stream_t strout, | 39 | { |
47 | int flags); | 40 | MU_TLS_CLIENT, |
48 | extern int mu_tls_client_stream_create (mu_stream_t *stream, | 41 | MU_TLS_SERVER |
49 | mu_stream_t strin, mu_stream_t strout, | 42 | }; |
50 | int flags); | ||
51 | |||
52 | extern int mu_check_tls_environment (void); | ||
53 | extern int mu_init_tls_libs (int x509); | ||
54 | extern void mu_deinit_tls_libs (void); | ||
55 | 43 | ||
56 | extern int mu_tls_enable; | 44 | extern int mu_tls_enable; |
45 | extern int mu_tls_cert_file_checks; | ||
46 | extern int mu_tls_key_file_checks; | ||
47 | extern int mu_tls_ca_file_checks; | ||
48 | |||
49 | #define MU_TLS_CERT_FILE_CHECKS \ | ||
50 | (MU_FILE_SAFETY_GROUP_WRITABLE \ | ||
51 | | MU_FILE_SAFETY_GROUP_WRITABLE \ | ||
52 | | MU_FILE_SAFETY_LINKED_WRDIR) | ||
53 | |||
54 | #define MU_TLS_KEY_FILE_CHECKS \ | ||
55 | (MU_FILE_SAFETY_ALL & ~MU_FILE_SAFETY_OWNER_MISMATCH) | ||
56 | |||
57 | #define MU_TLS_CA_FILE_CHECKS \ | ||
58 | (MU_FILE_SAFETY_GROUP_WRITABLE \ | ||
59 | | MU_FILE_SAFETY_GROUP_WRITABLE \ | ||
60 | | MU_FILE_SAFETY_LINKED_WRDIR) | ||
61 | |||
62 | void mu_tls_cfg_init (void); | ||
63 | |||
64 | int mu_tls_stream_create (mu_stream_t *pstream, | ||
65 | mu_stream_t strin, mu_stream_t strout, | ||
66 | struct mu_tls_config const *conf, | ||
67 | enum mu_tls_type type, | ||
68 | int flags); | ||
69 | int mu_tls_client_stream_create (mu_stream_t *pstream, | ||
70 | mu_stream_t strin, mu_stream_t strout, | ||
71 | int flags); | ||
72 | |||
73 | void mu_deinit_tls_libs (void); | ||
74 | int mu_init_tls_libs (void); | ||
75 | |||
76 | enum mu_tls_config_status | ||
77 | { | ||
78 | MU_TLS_CONFIG_OK, /* Configuration OK */ | ||
79 | MU_TLS_CONFIG_NULL, /* Configuration is empty */ | ||
80 | MU_TLS_CONFIG_UNSAFE, /* At least one file is considered unsafe */ | ||
81 | MU_TLS_CONFIG_FAIL /* Some files absent (or other system error) */ | ||
82 | }; | ||
83 | |||
84 | int mu_tls_config_check (struct mu_tls_config const *conf, int verbose); | ||
57 | 85 | ||
58 | extern struct mu_cli_capa mu_cli_capa_tls; | 86 | extern struct mu_cli_capa mu_cli_capa_tls; |
59 | 87 | ... | ... |
... | @@ -161,7 +161,7 @@ dup_container (struct mu_cfg_cont **pcont) | ... | @@ -161,7 +161,7 @@ dup_container (struct mu_cfg_cont **pcont) |
161 | newcont->v.section.ident = oldcont->v.section.ident; | 161 | newcont->v.section.ident = oldcont->v.section.ident; |
162 | newcont->v.section.label = oldcont->v.section.label; | 162 | newcont->v.section.label = oldcont->v.section.label; |
163 | newcont->v.section.parser = oldcont->v.section.parser; | 163 | newcont->v.section.parser = oldcont->v.section.parser; |
164 | newcont->v.section.target = oldcont->v.section.target; | 164 | newcont->v.section.data = oldcont->v.section.data; |
165 | newcont->v.section.offset = oldcont->v.section.offset; | 165 | newcont->v.section.offset = oldcont->v.section.offset; |
166 | newcont->v.section.docstring = oldcont->v.section.docstring; | 166 | newcont->v.section.docstring = oldcont->v.section.docstring; |
167 | newcont->v.section.children = NULL; | 167 | newcont->v.section.children = NULL; |
... | @@ -281,11 +281,27 @@ mu_cfg_section_add_params (struct mu_cfg_section *sect, | ... | @@ -281,11 +281,27 @@ mu_cfg_section_add_params (struct mu_cfg_section *sect, |
281 | switch (c->type) | 281 | switch (c->type) |
282 | { | 282 | { |
283 | case mu_cfg_cont_section: | 283 | case mu_cfg_cont_section: |
284 | c->v.section.offset += param->offset; | 284 | if (param->data) |
285 | { | ||
286 | c->v.section.data = param->data; | ||
287 | c->v.section.offset = param->offset; | ||
288 | } | ||
289 | else if (c->v.section.data) | ||
290 | /* Keep data & offset */; | ||
291 | else | ||
292 | c->v.section.offset += param->offset; | ||
285 | break; | 293 | break; |
286 | 294 | ||
287 | case mu_cfg_cont_param: | 295 | case mu_cfg_cont_param: |
288 | container->v.param.offset += param->offset; | 296 | if (param->data) |
297 | { | ||
298 | container->v.param.data = param->data; | ||
299 | container->v.param.offset = param->offset; | ||
300 | } | ||
301 | else if (container->v.param.data) | ||
302 | /* Keep data & offset */; | ||
303 | else | ||
304 | container->v.param.offset += param->offset; | ||
289 | break; | 305 | break; |
290 | } | 306 | } |
291 | mu_cfg_section_add_container (sect, c); | 307 | mu_cfg_section_add_container (sect, c); |
... | @@ -298,7 +314,7 @@ mu_cfg_section_add_params (struct mu_cfg_section *sect, | ... | @@ -298,7 +314,7 @@ mu_cfg_section_add_params (struct mu_cfg_section *sect, |
298 | mu_config_clone_container (container); | 314 | mu_config_clone_container (container); |
299 | if (mu_refcount_value (container->refcount) > 1) | 315 | if (mu_refcount_value (container->refcount) > 1) |
300 | dup_container (&container); | 316 | dup_container (&container); |
301 | container->v.section.target = param->data; | 317 | container->v.section.data = param->data; |
302 | container->v.section.offset = param->offset; | 318 | container->v.section.offset = param->offset; |
303 | } | 319 | } |
304 | } | 320 | } | ... | ... |
... | @@ -972,10 +972,14 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data) | ... | @@ -972,10 +972,14 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data) |
972 | } | 972 | } |
973 | if (!sec->children) | 973 | if (!sec->children) |
974 | return MU_CFG_ITER_SKIP; | 974 | return MU_CFG_ITER_SKIP; |
975 | if (sdata->list->sec->target) | 975 | if (sec->data) |
976 | sec->target = sec->data; | ||
977 | else if (sdata->list->sec->target) | ||
976 | sec->target = (char*)sdata->list->sec->target + sec->offset; | 978 | sec->target = (char*)sdata->list->sec->target + sec->offset; |
977 | else if (sdata->target) | 979 | else if (sdata->target) |
978 | sec->target = (char*)sdata->target + sec->offset; | 980 | sec->target = (char*)sdata->target + sec->offset; |
981 | else | ||
982 | sec->target = NULL; | ||
979 | if (sec->parser) | 983 | if (sec->parser) |
980 | { | 984 | { |
981 | mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, | 985 | mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, | ... | ... |
... | @@ -216,6 +216,12 @@ mu_ip_server_set_data (mu_ip_server_t srv, | ... | @@ -216,6 +216,12 @@ mu_ip_server_set_data (mu_ip_server_t srv, |
216 | return 0; | 216 | return 0; |
217 | } | 217 | } |
218 | 218 | ||
219 | void * | ||
220 | mu_ip_server_get_data (mu_ip_server_t tcpsrv) | ||
221 | { | ||
222 | return tcpsrv->data; | ||
223 | } | ||
224 | |||
219 | int | 225 | int |
220 | mu_address_family_to_domain (int family) | 226 | mu_address_family_to_domain (int family) |
221 | { | 227 | { | ... | ... |
... | @@ -77,7 +77,7 @@ struct _mu_m_server | ... | @@ -77,7 +77,7 @@ struct _mu_m_server |
77 | mu_list_t srvlist; /* A list of configured mu_ip_server_t | 77 | mu_list_t srvlist; /* A list of configured mu_ip_server_t |
78 | objects. It is cleared after the objects | 78 | objects. It is cleared after the objects |
79 | are opened and attached to the server. */ | 79 | are opened and attached to the server. */ |
80 | 80 | mu_m_server_preflight_fp preflight; /* Pre-flight check function */ | |
81 | mu_m_server_handler_fp conn; /* Connection handler function. */ | 81 | mu_m_server_handler_fp conn; /* Connection handler function. */ |
82 | mu_m_server_handler_fp prefork;/* Pre-fork function. */ | 82 | mu_m_server_handler_fp prefork;/* Pre-fork function. */ |
83 | void *data; /* User-supplied data for conn and prefork. */ | 83 | void *data; /* User-supplied data for conn and prefork. */ |
... | @@ -366,6 +366,12 @@ mu_m_server_set_strexit (mu_m_server_t srv, const char *(*fun) (int)) | ... | @@ -366,6 +366,12 @@ mu_m_server_set_strexit (mu_m_server_t srv, const char *(*fun) (int)) |
366 | srv->strexit = fun; | 366 | srv->strexit = fun; |
367 | } | 367 | } |
368 | 368 | ||
369 | void | ||
370 | mu_m_server_set_preflight (mu_m_server_t srv, mu_m_server_preflight_fp fun) | ||
371 | { | ||
372 | srv->preflight = fun; | ||
373 | } | ||
374 | |||
369 | int | 375 | int |
370 | mu_m_server_get_srvlist (mu_m_server_t srv, mu_list_t *plist) | 376 | mu_m_server_get_srvlist (mu_m_server_t srv, mu_list_t *plist) |
371 | { | 377 | { |
... | @@ -565,6 +571,7 @@ mu_m_server_destroy (mu_m_server_t *pmsrv) | ... | @@ -565,6 +571,7 @@ mu_m_server_destroy (mu_m_server_t *pmsrv) |
565 | { | 571 | { |
566 | mu_m_server_t msrv = *pmsrv; | 572 | mu_m_server_t msrv = *pmsrv; |
567 | mu_list_remove (m_server_list, msrv); | 573 | mu_list_remove (m_server_list, msrv); |
574 | mu_list_destroy (&msrv->srvlist); | ||
568 | mu_server_destroy (&msrv->server); | 575 | mu_server_destroy (&msrv->server); |
569 | free (msrv->child_pid); | 576 | free (msrv->child_pid); |
570 | /* FIXME: Send processes the TERM signal here?*/ | 577 | /* FIXME: Send processes the TERM signal here?*/ |
... | @@ -594,17 +601,16 @@ tcp_conn_free (void *conn_data, void *server_data) | ... | @@ -594,17 +601,16 @@ tcp_conn_free (void *conn_data, void *server_data) |
594 | } | 601 | } |
595 | 602 | ||
596 | static int | 603 | static int |
597 | _open_conn (void *item, void *data) | 604 | open_connection (mu_ip_server_t tcpsrv, mu_m_server_t msrv) |
598 | { | 605 | { |
599 | mu_ip_server_t tcpsrv = item; | ||
600 | mu_m_server_t msrv = data; | ||
601 | int rc = mu_ip_server_open (tcpsrv); | 606 | int rc = mu_ip_server_open (tcpsrv); |
602 | if (rc) | 607 | if (rc) |
603 | { | 608 | { |
604 | mu_error (_("cannot open connection on %s: %s"), | 609 | mu_error (_("cannot open connection on %s: %s"), |
605 | mu_ip_server_addrstr (tcpsrv), mu_strerror (rc)); | 610 | mu_ip_server_addrstr (tcpsrv), mu_strerror (rc)); |
606 | return 0; | 611 | return rc; |
607 | } | 612 | } |
613 | |||
608 | rc = mu_server_add_connection (msrv->server, | 614 | rc = mu_server_add_connection (msrv->server, |
609 | mu_ip_server_get_fd (tcpsrv), | 615 | mu_ip_server_get_fd (tcpsrv), |
610 | tcpsrv, | 616 | tcpsrv, |
... | @@ -614,9 +620,8 @@ _open_conn (void *item, void *data) | ... | @@ -614,9 +620,8 @@ _open_conn (void *item, void *data) |
614 | mu_error (_("cannot add connection %s: %s"), | 620 | mu_error (_("cannot add connection %s: %s"), |
615 | mu_ip_server_addrstr (tcpsrv), mu_strerror (rc)); | 621 | mu_ip_server_addrstr (tcpsrv), mu_strerror (rc)); |
616 | mu_ip_server_shutdown (tcpsrv); | 622 | mu_ip_server_shutdown (tcpsrv); |
617 | mu_ip_server_destroy (&tcpsrv); | ||
618 | } | 623 | } |
619 | return 0; | 624 | return rc; |
620 | } | 625 | } |
621 | 626 | ||
622 | int | 627 | int |
... | @@ -624,16 +629,36 @@ mu_m_server_run (mu_m_server_t msrv) | ... | @@ -624,16 +629,36 @@ mu_m_server_run (mu_m_server_t msrv) |
624 | { | 629 | { |
625 | int rc; | 630 | int rc; |
626 | size_t count; | 631 | size_t count; |
627 | mode_t saved_umask = umask (0117); | 632 | mode_t saved_umask; |
628 | mu_list_foreach (msrv->srvlist, _open_conn, msrv); | 633 | mu_iterator_t itr; |
634 | |||
635 | saved_umask = umask (0117); | ||
636 | mu_list_get_iterator (msrv->srvlist, &itr); | ||
637 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) | ||
638 | { | ||
639 | mu_ip_server_t tcpsrv; | ||
640 | mu_iterator_current (itr, (void**) &tcpsrv); | ||
641 | if (open_connection (tcpsrv, msrv)) | ||
642 | { | ||
643 | mu_iterator_ctl (itr, mu_itrctl_delete_nd, NULL); | ||
644 | mu_ip_server_destroy (&tcpsrv); | ||
645 | } | ||
646 | } | ||
629 | umask (saved_umask); | 647 | umask (saved_umask); |
630 | mu_list_destroy (&msrv->srvlist); | 648 | mu_iterator_destroy (&itr); |
649 | |||
631 | MU_ASSERT (mu_server_count (msrv->server, &count)); | 650 | MU_ASSERT (mu_server_count (msrv->server, &count)); |
632 | if (count == 0) | 651 | if (count == 0) |
633 | { | 652 | { |
634 | mu_error (_("no servers configured: exiting")); | 653 | mu_error (_("no servers configured: exiting")); |
635 | exit (1); | 654 | exit (1); |
636 | } | 655 | } |
656 | if (msrv->preflight && msrv->preflight (msrv)) | ||
657 | { | ||
658 | mu_error (_("%s: preflight check failed"), msrv->ident); | ||
659 | return MU_ERR_FAILURE; | ||
660 | } | ||
661 | |||
637 | if (msrv->ident) | 662 | if (msrv->ident) |
638 | mu_diag_output (MU_DIAG_INFO, _("%s started"), msrv->ident); | 663 | mu_diag_output (MU_DIAG_INFO, _("%s started"), msrv->ident); |
639 | rc = mu_server_run (msrv->server); | 664 | rc = mu_server_run (msrv->server); |
... | @@ -642,8 +667,6 @@ mu_m_server_run (mu_m_server_t msrv) | ... | @@ -642,8 +667,6 @@ mu_m_server_run (mu_m_server_t msrv) |
642 | mu_diag_output (MU_DIAG_INFO, _("%s terminated"), msrv->ident); | 667 | mu_diag_output (MU_DIAG_INFO, _("%s terminated"), msrv->ident); |
643 | return rc; | 668 | return rc; |
644 | } | 669 | } |
645 | |||
646 | |||
647 | 670 | ||
648 | int | 671 | int |
649 | mu_m_server_check_acl (mu_m_server_t msrv, struct sockaddr *s, int salen) | 672 | mu_m_server_check_acl (mu_m_server_t msrv, struct sockaddr *s, int salen) | ... | ... |
... | @@ -29,9 +29,18 @@ libmu_auth_la_SOURCES = \ | ... | @@ -29,9 +29,18 @@ libmu_auth_la_SOURCES = \ |
29 | radius.c\ | 29 | radius.c\ |
30 | sql.c\ | 30 | sql.c\ |
31 | sql.h\ | 31 | sql.h\ |
32 | tls.c\ | ||
33 | virtual.c | 32 | virtual.c |
34 | 33 | ||
34 | libmu_auth_la_SOURCES += tlsconf.c tlsvar.c | ||
35 | |||
36 | if MU_COND_GNUTLS | ||
37 | libmu_auth_la_SOURCES += \ | ||
38 | tls.c\ | ||
39 | tlsiostr.c | ||
40 | else | ||
41 | libmu_auth_la_SOURCES += notls.c | ||
42 | endif | ||
43 | |||
35 | libmu_auth_la_LIBADD = ${MU_LIB_MAILUTILS} @MU_AUTHLIBS@ @SQLLIB@ @LTLIBINTL@ | 44 | libmu_auth_la_LIBADD = ${MU_LIB_MAILUTILS} @MU_AUTHLIBS@ @SQLLIB@ @LTLIBINTL@ |
36 | libmu_auth_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ | 45 | libmu_auth_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ |
37 | libmu_auth_la_DEPENDENCIES = @SQLLIB_DEPENDENCY@ | 46 | libmu_auth_la_DEPENDENCIES = @SQLLIB_DEPENDENCY@ | ... | ... |
libmu_auth/notls.c
0 → 100644
1 | /* Declare fail-only TLS interfaces in the absense of GNU TLS */ | ||
2 | #if HAVE_CONFIG_H | ||
3 | # include <config.h> | ||
4 | #endif | ||
5 | #include <mailutils/tls.h> | ||
6 | #include <mailutils/errno.h> | ||
7 | |||
8 | int | ||
9 | mu_tls_stream_create (mu_stream_t *pstream, | ||
10 | mu_stream_t strin, mu_stream_t strout, | ||
11 | struct mu_tls_config const *conf, | ||
12 | enum mu_tls_type type, | ||
13 | int flags) | ||
14 | { | ||
15 | return ENOSYS; | ||
16 | } | ||
17 | |||
18 | void | ||
19 | mu_deinit_tls_libs (void) | ||
20 | { | ||
21 | } | ||
22 | |||
23 | int | ||
24 | mu_init_tls_libs (void) | ||
25 | { | ||
26 | mu_tls_enable = 0; | ||
27 | return 0; | ||
28 | } | ||
29 |
... | @@ -20,123 +20,33 @@ | ... | @@ -20,123 +20,33 @@ |
20 | # include <config.h> | 20 | # include <config.h> |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | 23 | #include <stdlib.h> |
25 | #include <unistd.h> | ||
26 | #include <sys/types.h> | ||
27 | #include <sys/stat.h> | ||
28 | #include <string.h> | ||
29 | 24 | ||
30 | #include <mailutils/error.h> | ||
31 | #include <mailutils/mu_auth.h> | ||
32 | #include <mailutils/tls.h> | 25 | #include <mailutils/tls.h> |
33 | #include <mailutils/nls.h> | 26 | #include <mailutils/nls.h> |
34 | #include <mailutils/stream.h> | 27 | #include <mailutils/stream.h> |
28 | #include <mailutils/error.h> | ||
35 | #include <mailutils/errno.h> | 29 | #include <mailutils/errno.h> |
36 | #include <mailutils/util.h> | ||
37 | #include <mailutils/property.h> | 30 | #include <mailutils/property.h> |
38 | #include <mailutils/cli.h> | 31 | #include <mailutils/mu_auth.h> |
39 | |||
40 | #define SSL_CERT_FILE_CHECKS (MU_FILE_SAFETY_GROUP_WRITABLE | \ | ||
41 | MU_FILE_SAFETY_GROUP_WRITABLE | \ | ||
42 | MU_FILE_SAFETY_LINKED_WRDIR) | ||
43 | |||
44 | #define SSL_KEY_FILE_CHECKS (MU_FILE_SAFETY_ALL & \ | ||
45 | ~MU_FILE_SAFETY_OWNER_MISMATCH) | ||
46 | |||
47 | #define SSL_CA_FILE_CHECKS (MU_FILE_SAFETY_GROUP_WRITABLE | \ | ||
48 | MU_FILE_SAFETY_GROUP_WRITABLE | \ | ||
49 | MU_FILE_SAFETY_LINKED_WRDIR) | ||
50 | |||
51 | struct mu_tls_module_config mu_tls_module_config = { | ||
52 | #ifdef WITH_TLS | ||
53 | 1, /* enable by default */ | ||
54 | |||
55 | NULL, /* Certificate file */ | ||
56 | SSL_CERT_FILE_CHECKS, | ||
57 | |||
58 | NULL, /* Key file */ | ||
59 | SSL_KEY_FILE_CHECKS, /* Stringent safety checks for keys */ | ||
60 | |||
61 | NULL, /* CA file */ | ||
62 | SSL_CA_FILE_CHECKS | ||
63 | #else | ||
64 | 0 | ||
65 | #endif | ||
66 | }; | ||
67 | |||
68 | #ifdef WITH_TLS | ||
69 | 32 | ||
70 | #include <gnutls/gnutls.h> | 33 | #include <gnutls/gnutls.h> |
71 | #include <mailutils/sys/tls-stream.h> | 34 | #include <mailutils/sys/tls-stream.h> |
72 | 35 | ||
73 | static gnutls_certificate_server_credentials x509_cred; | 36 | static void |
74 | |||
75 | /* Return: zero means NOT READY, one means READY */ | ||
76 | int | ||
77 | mu_check_tls_environment (void) | ||
78 | { | ||
79 | if (!mu_tls_module_config.enable) | ||
80 | return 0; | ||
81 | if (mu_tls_module_config.ssl_cert && mu_tls_module_config.ssl_key) | ||
82 | { | ||
83 | int rc = mu_file_safety_check (mu_tls_module_config.ssl_cert, | ||
84 | mu_tls_module_config.ssl_cert_safety_checks, | ||
85 | -1, NULL); | ||
86 | if (rc) | ||
87 | { | ||
88 | mu_error ("%s: %s", mu_tls_module_config.ssl_cert, | ||
89 | mu_strerror (rc)); | ||
90 | return 0; | ||
91 | } | ||
92 | rc = mu_file_safety_check (mu_tls_module_config.ssl_key, | ||
93 | mu_tls_module_config.ssl_key_safety_checks, | ||
94 | -1, NULL); | ||
95 | if (rc) | ||
96 | { | ||
97 | mu_error ("%s: %s", mu_tls_module_config.ssl_key, | ||
98 | mu_strerror (rc)); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | if (mu_tls_module_config.ssl_cafile) | ||
103 | { | ||
104 | rc = mu_file_safety_check (mu_tls_module_config.ssl_cafile, | ||
105 | mu_tls_module_config.ssl_cafile_safety_checks, | ||
106 | -1, NULL); | ||
107 | if (rc) | ||
108 | { | ||
109 | mu_error ("%s: %s", mu_tls_module_config.ssl_cafile, | ||
110 | mu_strerror (rc)); | ||
111 | return 0; | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | else | ||
116 | return 0; | ||
117 | |||
118 | return 1; | ||
119 | } | ||
120 | |||
121 | int mu_tls_enable = 0; | ||
122 | |||
123 | #ifdef DEBUG_TLS | ||
124 | void | ||
125 | _mu_gtls_logger(int level, const char *text) | 37 | _mu_gtls_logger(int level, const char *text) |
126 | { | 38 | { |
127 | mu_diag_output (MU_DIAG_DEBUG, "GnuTLS(%d): %s", level, text); | 39 | int len = strlen (text); |
40 | if (text[len-1] == '\n') | ||
41 | len--; | ||
42 | mu_diag_output (MU_DIAG_DEBUG, "GnuTLS(%d): %.*s", level, len, text); | ||
128 | } | 43 | } |
129 | #endif | ||
130 | 44 | ||
131 | void | 45 | void |
132 | mu_deinit_tls_libs (void) | 46 | mu_deinit_tls_libs (void) |
133 | { | 47 | { |
134 | if (mu_tls_enable) | 48 | if (mu_tls_enable) |
135 | { | 49 | gnutls_global_deinit (); |
136 | if (x509_cred) | ||
137 | gnutls_certificate_free_credentials (x509_cred); | ||
138 | gnutls_global_deinit (); | ||
139 | } | ||
140 | mu_tls_enable = 0; | 50 | mu_tls_enable = 0; |
141 | } | 51 | } |
142 | 52 | ||
... | @@ -147,270 +57,31 @@ _onexit_deinit (void *ptr MU_ARG_UNUSED) | ... | @@ -147,270 +57,31 @@ _onexit_deinit (void *ptr MU_ARG_UNUSED) |
147 | } | 57 | } |
148 | 58 | ||
149 | int | 59 | int |
150 | mu_init_tls_libs (int x509_setup) | 60 | mu_init_tls_libs (void) |
151 | { | 61 | { |
152 | if (!mu_tls_enable) | 62 | if (!mu_tls_enable) |
153 | { | 63 | { |
154 | int rc; | 64 | int rc = gnutls_global_init (); |
155 | if ((rc = gnutls_global_init ()) == GNUTLS_E_SUCCESS) | 65 | if (rc == GNUTLS_E_SUCCESS) |
156 | mu_tls_enable = 1; | ||
157 | else | ||
158 | { | ||
159 | mu_error ("gnutls_global_init: %s", gnutls_strerror (rc)); | ||
160 | return 0; | ||
161 | } | ||
162 | mu_onexit (_onexit_deinit, NULL); | ||
163 | } | ||
164 | |||
165 | if (x509_setup && !x509_cred) | ||
166 | { | ||
167 | gnutls_certificate_allocate_credentials (&x509_cred); | ||
168 | if (mu_tls_module_config.ssl_cafile) | ||
169 | gnutls_certificate_set_x509_trust_file (x509_cred, | ||
170 | mu_tls_module_config.ssl_cafile, | ||
171 | GNUTLS_X509_FMT_PEM); | ||
172 | |||
173 | gnutls_certificate_set_x509_key_file (x509_cred, | ||
174 | mu_tls_module_config.ssl_cert, | ||
175 | mu_tls_module_config.ssl_key, | ||
176 | GNUTLS_X509_FMT_PEM); | ||
177 | } | ||
178 | |||
179 | #ifdef DEBUG_TLS | ||
180 | gnutls_global_set_log_function (_mu_gtls_logger); | ||
181 | gnutls_global_set_log_level (110); | ||
182 | #endif | ||
183 | return mu_tls_enable; | ||
184 | } | ||
185 | |||
186 | static char default_priority_string[] = "NORMAL"; | ||
187 | |||
188 | static gnutls_session_t | ||
189 | initialize_tls_session (void) | ||
190 | { | ||
191 | gnutls_session_t session = 0; | ||
192 | |||
193 | gnutls_init (&session, GNUTLS_SERVER); | ||
194 | gnutls_priority_set_direct (session, | ||
195 | mu_tls_module_config.priorities | ||
196 | ? mu_tls_module_config.priorities | ||
197 | : default_priority_string, | ||
198 | NULL); | ||
199 | gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred); | ||
200 | gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST); | ||
201 | |||
202 | return session; | ||
203 | } | ||
204 | |||
205 | |||
206 | /* ************************* TLS Stream Support **************************** */ | ||
207 | |||
208 | static int | ||
209 | _tls_io_close (mu_stream_t stream) | ||
210 | { | ||
211 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
212 | |||
213 | return mu_stream_close (sp->transport); | ||
214 | } | ||
215 | |||
216 | static void | ||
217 | _tls_io_done (struct _mu_stream *stream) | ||
218 | { | ||
219 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
220 | mu_stream_unref (sp->transport); | ||
221 | } | ||
222 | |||
223 | static int | ||
224 | _tls_io_flush (struct _mu_stream *stream) | ||
225 | { | ||
226 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
227 | return mu_stream_flush (sp->transport); | ||
228 | } | ||
229 | |||
230 | static int | ||
231 | _tls_io_read (struct _mu_stream *stream, char *buf, size_t bufsize, | ||
232 | size_t *pnread) | ||
233 | { | ||
234 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
235 | int rc; | ||
236 | |||
237 | if (sp->up->state != state_open) | ||
238 | return EINVAL; | ||
239 | rc = gnutls_record_recv (sp->up->session, buf, bufsize); | ||
240 | if (rc >= 0) | ||
241 | { | ||
242 | *pnread = rc; | ||
243 | return 0; | ||
244 | } | ||
245 | sp->up->tls_err = rc; | ||
246 | return EIO; | ||
247 | } | ||
248 | |||
249 | static int | ||
250 | _tls_io_write (struct _mu_stream *stream, const char *buf, size_t bufsize, | ||
251 | size_t *pnwrite) | ||
252 | { | ||
253 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
254 | int rc; | ||
255 | |||
256 | if (sp->up->state != state_open) | ||
257 | return EINVAL; | ||
258 | |||
259 | /* gnutls_record_send() docs say: | ||
260 | If the EINTR is returned by the internal push function (write()) | ||
261 | then GNUTLS_E_INTERRUPTED, will be returned. If GNUTLS_E_INTERRUPTED or | ||
262 | GNUTLS_E_AGAIN is returned you must call this function again, with the | ||
263 | same parameters. Otherwise the write operation will be | ||
264 | corrupted and the connection will be terminated. */ | ||
265 | |||
266 | do | ||
267 | rc = gnutls_record_send (sp->up->session, buf, bufsize); | ||
268 | while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN); | ||
269 | |||
270 | if (rc < 0) | ||
271 | { | ||
272 | sp->up->tls_err = rc; | ||
273 | return EIO; | ||
274 | } | ||
275 | |||
276 | *pnwrite = rc; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int | ||
282 | _tls_rd_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp) | ||
283 | { | ||
284 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
285 | int rc = EINVAL; | ||
286 | |||
287 | if (*pflags == MU_STREAM_READY_RD) | ||
288 | rc = mu_stream_wait (sp->transport, pflags, tvp); | ||
289 | return rc; | ||
290 | } | ||
291 | |||
292 | static int | ||
293 | _tls_wr_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp) | ||
294 | { | ||
295 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
296 | int rc = EINVAL; | ||
297 | |||
298 | if (*pflags == MU_STREAM_READY_WR) | ||
299 | rc = mu_stream_wait (sp->transport, pflags, tvp); | ||
300 | return rc; | ||
301 | } | ||
302 | |||
303 | static int | ||
304 | get_cipher_info (gnutls_session_t session, mu_property_t *pprop) | ||
305 | { | ||
306 | mu_property_t prop; | ||
307 | const char *s; | ||
308 | int rc; | ||
309 | |||
310 | if (!pprop) | ||
311 | return EINVAL; | ||
312 | |||
313 | rc = mu_property_create_init (&prop, mu_assoc_property_init, NULL); | ||
314 | if (rc) | ||
315 | return rc; | ||
316 | |||
317 | s = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); | ||
318 | mu_property_set_value (prop, "protocol", s, 1); | ||
319 | |||
320 | s = gnutls_cipher_get_name (gnutls_cipher_get (session)); | ||
321 | mu_property_set_value (prop, "cipher", s, 1); | ||
322 | |||
323 | s = gnutls_mac_get_name (gnutls_mac_get (session)); | ||
324 | mu_property_set_value (prop, "mac", s, 1); | ||
325 | |||
326 | *pprop = prop; | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int | ||
332 | _tls_io_ioctl (struct _mu_stream *stream, int code, int opcode, void *arg) | ||
333 | { | ||
334 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
335 | |||
336 | switch (code) | ||
337 | { | ||
338 | case MU_IOCTL_TRANSPORT: | ||
339 | if (!arg) | ||
340 | return EINVAL; | ||
341 | else | ||
342 | { | 66 | { |
343 | mu_transport_t *ptrans = arg; | 67 | mu_tls_enable = 1; |
344 | switch (opcode) | 68 | mu_onexit (_onexit_deinit, NULL); |
69 | if (mu_debug_level_p (MU_DEBCAT_TLS, MU_DEBUG_PROT)) | ||
345 | { | 70 | { |
346 | case MU_IOCTL_OP_GET: | 71 | gnutls_global_set_log_function (_mu_gtls_logger); |
347 | ptrans[0] = (mu_transport_t) sp->transport; | 72 | gnutls_global_set_log_level (110); |
348 | ptrans[1] = NULL; | ||
349 | break; | ||
350 | |||
351 | case MU_IOCTL_OP_SET: | ||
352 | return ENOSYS; | ||
353 | |||
354 | default: | ||
355 | return EINVAL; | ||
356 | } | 73 | } |
357 | } | 74 | } |
358 | break; | 75 | else |
359 | |||
360 | case MU_IOCTL_TLSSTREAM: | ||
361 | switch (opcode) | ||
362 | { | 76 | { |
363 | case MU_IOCTL_TLS_GET_CIPHER_INFO: | 77 | mu_error ("gnutls_global_init: %s", gnutls_strerror (rc)); |
364 | return get_cipher_info (sp->up->session, arg); | ||
365 | |||
366 | default: | ||
367 | return EINVAL; | ||
368 | } | 78 | } |
369 | break; | ||
370 | |||
371 | default: | ||
372 | return ENOSYS; | ||
373 | } | 79 | } |
374 | return 0; | 80 | return mu_tls_enable; |
375 | } | ||
376 | |||
377 | static int | ||
378 | _mu_tls_io_stream_create (mu_stream_t *pstream, | ||
379 | mu_stream_t transport, int flags, | ||
380 | struct _mu_tls_stream *master) | ||
381 | { | ||
382 | struct _mu_tls_io_stream *sp; | ||
383 | |||
384 | sp = (struct _mu_tls_io_stream *) | ||
385 | _mu_stream_create (sizeof (*sp), (flags & MU_STREAM_RDWR) | _MU_STR_OPEN); | ||
386 | if (!sp) | ||
387 | return ENOMEM; | ||
388 | |||
389 | if (flags & MU_STREAM_READ) | ||
390 | { | ||
391 | sp->stream.read = _tls_io_read; | ||
392 | sp->stream.wait = _tls_rd_wait; | ||
393 | mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_full, 0); | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | sp->stream.write = _tls_io_write; | ||
398 | sp->stream.wait = _tls_wr_wait; | ||
399 | mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 0); | ||
400 | } | ||
401 | sp->stream.flush = _tls_io_flush; | ||
402 | sp->stream.close = _tls_io_close; | ||
403 | sp->stream.done = _tls_io_done; | ||
404 | sp->stream.ctl = _tls_io_ioctl; | ||
405 | |||
406 | mu_stream_ref (transport); | ||
407 | sp->transport = transport; | ||
408 | sp->up = master; | ||
409 | *pstream = (mu_stream_t) sp; | ||
410 | return 0; | ||
411 | } | 81 | } |
412 | |||
413 | 82 | ||
83 | /* TLS push & pull functions */ | ||
84 | |||
414 | static ssize_t | 85 | static ssize_t |
415 | _tls_stream_pull (gnutls_transport_ptr_t fd, void *buf, size_t size) | 86 | _tls_stream_pull (gnutls_transport_ptr_t fd, void *buf, size_t size) |
416 | { | 87 | { |
... | @@ -443,82 +114,125 @@ _tls_stream_push (gnutls_transport_ptr_t fd, const void *buf, size_t size) | ... | @@ -443,82 +114,125 @@ _tls_stream_push (gnutls_transport_ptr_t fd, const void *buf, size_t size) |
443 | mu_stream_flush (stream); | 114 | mu_stream_flush (stream); |
444 | return size; | 115 | return size; |
445 | } | 116 | } |
446 | |||
447 | 117 | ||
448 | static int | 118 | static char default_priority_string[] = "NORMAL"; |
449 | _tls_server_open (mu_stream_t stream) | ||
450 | { | ||
451 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; | ||
452 | int rc = 0; | ||
453 | mu_transport_t transport[2]; | ||
454 | |||
455 | if (!mu_tls_module_config.enable) | ||
456 | return MU_ERR_DISABLED; | ||
457 | if (!stream || sp->state != state_init) | ||
458 | return EINVAL; | ||
459 | |||
460 | if (!mu_init_tls_libs (1)) | ||
461 | return MU_ERR_FAILURE; | ||
462 | |||
463 | sp->session = initialize_tls_session (); | ||
464 | mu_stream_ioctl (stream, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, transport); | ||
465 | gnutls_transport_set_ptr2 (sp->session, | ||
466 | (gnutls_transport_ptr_t) transport[0], | ||
467 | (gnutls_transport_ptr_t) transport[1]); | ||
468 | gnutls_transport_set_pull_function (sp->session, _tls_stream_pull); | ||
469 | gnutls_transport_set_push_function (sp->session, _tls_stream_push); | ||
470 | |||
471 | rc = gnutls_handshake (sp->session); | ||
472 | if (rc < 0) | ||
473 | { | ||
474 | gnutls_deinit (sp->session); | ||
475 | sp->tls_err = rc; | ||
476 | return EIO; | ||
477 | } | ||
478 | sp->state = state_open; | ||
479 | return 0; | ||
480 | } | ||
481 | 119 | ||
482 | static int | 120 | static int |
483 | prepare_client_session (mu_stream_t stream) | 121 | prep_session (mu_stream_t stream) |
484 | { | 122 | { |
485 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; | 123 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; |
486 | int rc; | 124 | gnutls_certificate_credentials_t cred = NULL; |
487 | mu_transport_t transport[2]; | 125 | mu_transport_t transport[2]; |
126 | int rc; | ||
127 | const char *errp; | ||
488 | 128 | ||
489 | gnutls_init (&sp->session, GNUTLS_CLIENT); | 129 | if (!sp->cred) |
490 | gnutls_priority_set_direct (sp->session, | ||
491 | mu_tls_module_config.priorities | ||
492 | ? mu_tls_module_config.priorities | ||
493 | : default_priority_string, | ||
494 | NULL); | ||
495 | gnutls_certificate_allocate_credentials (&x509_cred); | ||
496 | if (mu_tls_module_config.ssl_cafile) | ||
497 | { | 130 | { |
498 | rc = gnutls_certificate_set_x509_trust_file (x509_cred, | 131 | rc = gnutls_certificate_allocate_credentials (&cred); |
499 | mu_tls_module_config.ssl_cafile, | 132 | if (rc) |
500 | GNUTLS_X509_FMT_PEM); | ||
501 | if (rc < 0) | ||
502 | { | 133 | { |
134 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
135 | ("gnutls_certificate_allocate_credentials: %s", | ||
136 | gnutls_strerror (rc))); | ||
503 | sp->tls_err = rc; | 137 | sp->tls_err = rc; |
504 | return -1; | 138 | return MU_ERR_FAILURE; |
139 | } | ||
140 | |||
141 | if (sp->conf.ca_file) | ||
142 | { | ||
143 | rc = gnutls_certificate_set_x509_trust_file (cred, sp->conf.ca_file, | ||
144 | GNUTLS_X509_FMT_PEM); | ||
145 | if (rc < 0) | ||
146 | { | ||
147 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
148 | ("can't use X509 CA file %s: %s", | ||
149 | sp->conf.ca_file, | ||
150 | gnutls_strerror (rc))); | ||
151 | goto cred_err; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | if (sp->conf.cert_file && sp->conf.key_file) | ||
156 | { | ||
157 | rc = gnutls_certificate_set_x509_key_file (cred, | ||
158 | sp->conf.cert_file, | ||
159 | sp->conf.key_file, | ||
160 | GNUTLS_X509_FMT_PEM); | ||
161 | if (rc != GNUTLS_E_SUCCESS) | ||
162 | { | ||
163 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
164 | ("can't use X509 cert/key pair (%s,%s): %s", | ||
165 | sp->conf.cert_file, | ||
166 | sp->conf.key_file, | ||
167 | gnutls_strerror (rc))); | ||
168 | goto cred_err; | ||
169 | } | ||
505 | } | 170 | } |
171 | sp->cred = cred; | ||
172 | } | ||
173 | |||
174 | rc = gnutls_init (&sp->session, sp->session_type); | ||
175 | if (rc != GNUTLS_E_SUCCESS) | ||
176 | { | ||
177 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
178 | ("failed to initialize session: %s", gnutls_strerror (rc))); | ||
179 | goto cred_err; | ||
506 | } | 180 | } |
507 | 181 | ||
508 | gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE, x509_cred); | 182 | rc = gnutls_priority_set_direct (sp->session, |
509 | 183 | sp->conf.priorities | |
510 | mu_stream_ioctl (stream, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, transport); | 184 | ? sp->conf.priorities |
185 | : default_priority_string, | ||
186 | &errp); | ||
187 | if (rc != GNUTLS_E_SUCCESS) | ||
188 | { | ||
189 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
190 | ("error setting priorities near %s: %s", | ||
191 | errp, gnutls_strerror (rc))); | ||
192 | goto cred_err; | ||
193 | } | ||
194 | |||
195 | rc = gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE, sp->cred); | ||
196 | if (rc) | ||
197 | { | ||
198 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
199 | ("gnutls_credentials_set: %s", gnutls_strerror (rc))); | ||
200 | goto sess_err; | ||
201 | } | ||
202 | |||
203 | if (sp->session_type == GNUTLS_SERVER) | ||
204 | gnutls_certificate_server_set_request (sp->session, GNUTLS_CERT_REQUEST); | ||
205 | |||
206 | rc = mu_stream_ioctl (stream, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, | ||
207 | transport); | ||
208 | if (rc) | ||
209 | { | ||
210 | mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_ioctl", NULL, rc); | ||
211 | abort (); /* should not happen */ | ||
212 | } | ||
213 | |||
511 | gnutls_transport_set_ptr2 (sp->session, | 214 | gnutls_transport_set_ptr2 (sp->session, |
512 | (gnutls_transport_ptr_t) transport[0], | 215 | (gnutls_transport_ptr_t) transport[0], |
513 | (gnutls_transport_ptr_t) transport[1]); | 216 | (gnutls_transport_ptr_t) transport[1]); |
514 | gnutls_transport_set_pull_function (sp->session, _tls_stream_pull); | 217 | gnutls_transport_set_pull_function (sp->session, _tls_stream_pull); |
515 | gnutls_transport_set_push_function (sp->session, _tls_stream_push); | 218 | gnutls_transport_set_push_function (sp->session, _tls_stream_push); |
516 | 219 | ||
517 | return 0; | 220 | return 0; |
221 | |||
222 | sess_err: | ||
223 | gnutls_deinit (sp->session); | ||
224 | cred_err: | ||
225 | if (sp->cred) | ||
226 | { | ||
227 | gnutls_certificate_free_credentials (sp->cred); | ||
228 | sp->cred = NULL; | ||
229 | } | ||
230 | sp->tls_err = rc; | ||
231 | return MU_ERR_FAILURE; | ||
518 | } | 232 | } |
519 | 233 | ||
520 | static int | 234 | static int |
521 | _tls_client_open (mu_stream_t stream) | 235 | _tls_open (mu_stream_t stream) |
522 | { | 236 | { |
523 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; | 237 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; |
524 | int rc = 0; | 238 | int rc = 0; |
... | @@ -527,32 +241,38 @@ _tls_client_open (mu_stream_t stream) | ... | @@ -527,32 +241,38 @@ _tls_client_open (mu_stream_t stream) |
527 | { | 241 | { |
528 | case state_closed: | 242 | case state_closed: |
529 | if (sp->session) | 243 | if (sp->session) |
530 | gnutls_deinit (sp->session); | 244 | { |
245 | gnutls_deinit (sp->session); | ||
246 | sp->session = NULL; | ||
247 | } | ||
531 | /* FALLTHROUGH */ | 248 | /* FALLTHROUGH */ |
532 | 249 | ||
533 | case state_init: | 250 | case state_init: |
534 | if (!mu_init_tls_libs (0)) | 251 | rc = prep_session (stream); |
535 | return MU_ERR_FAILURE; | 252 | if (rc) |
536 | prepare_client_session (stream); | 253 | break; |
537 | rc = gnutls_handshake (sp->session); | 254 | rc = gnutls_handshake (sp->session); |
538 | if (rc < 0) | 255 | if (rc != GNUTLS_E_SUCCESS) |
539 | { | 256 | { |
257 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
258 | ("gnutls_handshake: %s", gnutls_strerror (rc))); | ||
540 | sp->tls_err = rc; | 259 | sp->tls_err = rc; |
541 | gnutls_deinit (sp->session); | 260 | gnutls_deinit (sp->session); |
261 | sp->session = NULL; | ||
542 | sp->state = state_init; | 262 | sp->state = state_init; |
543 | return MU_ERR_FAILURE; | ||
544 | } | 263 | } |
264 | else | ||
265 | /* FIXME: if (ssl_cafile) verify_certificate (s->session); */ | ||
266 | sp->state = state_open; | ||
545 | break; | 267 | break; |
546 | 268 | ||
547 | default: | 269 | default: |
548 | return MU_ERR_FAILURE; | 270 | rc = MU_ERR_BADOP; |
549 | } | 271 | } |
550 | 272 | return rc; | |
551 | /* FIXME: if (ssl_cafile) verify_certificate (s->session); */ | ||
552 | sp->state = state_open; | ||
553 | return 0; | ||
554 | } | 273 | } |
555 | 274 | ||
275 | /* TLS stream */ | ||
556 | static int | 276 | static int |
557 | _tls_read (struct _mu_stream *str, char *buf, size_t bufsize, | 277 | _tls_read (struct _mu_stream *str, char *buf, size_t bufsize, |
558 | size_t *pnread) | 278 | size_t *pnread) |
... | @@ -570,6 +290,34 @@ _tls_write (struct _mu_stream *str, const char *buf, size_t bufsize, | ... | @@ -570,6 +290,34 @@ _tls_write (struct _mu_stream *str, const char *buf, size_t bufsize, |
570 | } | 290 | } |
571 | 291 | ||
572 | static int | 292 | static int |
293 | get_cipher_info (gnutls_session_t session, mu_property_t *pprop) | ||
294 | { | ||
295 | mu_property_t prop; | ||
296 | const char *s; | ||
297 | int rc; | ||
298 | |||
299 | if (!pprop) | ||
300 | return EINVAL; | ||
301 | |||
302 | rc = mu_property_create_init (&prop, mu_assoc_property_init, NULL); | ||
303 | if (rc) | ||
304 | return rc; | ||
305 | |||
306 | s = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); | ||
307 | mu_property_set_value (prop, "protocol", s, 1); | ||
308 | |||
309 | s = gnutls_cipher_get_name (gnutls_cipher_get (session)); | ||
310 | mu_property_set_value (prop, "cipher", s, 1); | ||
311 | |||
312 | s = gnutls_mac_get_name (gnutls_mac_get (session)); | ||
313 | mu_property_set_value (prop, "mac", s, 1); | ||
314 | |||
315 | *pprop = prop; | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int | ||
573 | _tls_ioctl (struct _mu_stream *stream, int code, int opcode, void *arg) | 321 | _tls_ioctl (struct _mu_stream *stream, int code, int opcode, void *arg) |
574 | { | 322 | { |
575 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; | 323 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; |
... | @@ -684,17 +432,18 @@ _tls_close (mu_stream_t stream) | ... | @@ -684,17 +432,18 @@ _tls_close (mu_stream_t stream) |
684 | return 0; | 432 | return 0; |
685 | } | 433 | } |
686 | 434 | ||
435 | static void free_conf (struct mu_tls_config *conf); | ||
436 | |||
687 | static void | 437 | static void |
688 | _tls_done (struct _mu_stream *stream) | 438 | _tls_done (struct _mu_stream *stream) |
689 | { | 439 | { |
690 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; | 440 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; |
691 | 441 | ||
692 | if (sp->session && sp->state == state_closed) | 442 | if (sp->session) |
693 | { | 443 | gnutls_deinit (sp->session); |
694 | gnutls_deinit (sp->session); | 444 | if (sp->cred) |
695 | sp->state = state_destroyed; | 445 | gnutls_certificate_free_credentials (sp->cred); |
696 | } | 446 | free_conf (&sp->conf); |
697 | |||
698 | mu_stream_destroy (&sp->transport[0]); | 447 | mu_stream_destroy (&sp->transport[0]); |
699 | mu_stream_destroy (&sp->transport[1]); | 448 | mu_stream_destroy (&sp->transport[1]); |
700 | } | 449 | } |
... | @@ -710,24 +459,121 @@ _tls_error_string (struct _mu_stream *stream, int rc) | ... | @@ -710,24 +459,121 @@ _tls_error_string (struct _mu_stream *stream, int rc) |
710 | return mu_strerror (rc); | 459 | return mu_strerror (rc); |
711 | } | 460 | } |
712 | 461 | ||
462 | static void | ||
463 | free_conf (struct mu_tls_config *conf) | ||
464 | { | ||
465 | free (conf->cert_file); | ||
466 | free (conf->key_file); | ||
467 | free (conf->ca_file); | ||
468 | } | ||
469 | |||
713 | static int | 470 | static int |
714 | _mu_tls_stream_create (mu_stream_t *pstream, | 471 | copy_conf (struct mu_tls_config *dst, struct mu_tls_config const *src) |
715 | int (*openfn) (mu_stream_t stream), | 472 | { |
716 | mu_stream_t strin, mu_stream_t strout, int flags) | 473 | if (src->cert_file) |
474 | { | ||
475 | dst->cert_file = strdup (src->cert_file); | ||
476 | if (!dst->cert_file) | ||
477 | return errno; | ||
478 | } | ||
479 | else | ||
480 | dst->cert_file = NULL; | ||
481 | |||
482 | if (src->key_file) | ||
483 | { | ||
484 | dst->key_file = strdup (src->key_file); | ||
485 | if (!dst->cert_file) | ||
486 | { | ||
487 | int rc = errno; | ||
488 | free (dst->cert_file); | ||
489 | return rc; | ||
490 | } | ||
491 | } | ||
492 | else | ||
493 | dst->key_file = NULL; | ||
494 | |||
495 | if (src->ca_file) | ||
496 | { | ||
497 | dst->ca_file = strdup (src->ca_file); | ||
498 | if (!dst->ca_file) | ||
499 | { | ||
500 | int rc = errno; | ||
501 | free (dst->cert_file); | ||
502 | free (dst->key_file); | ||
503 | return rc; | ||
504 | } | ||
505 | } | ||
506 | else | ||
507 | dst->ca_file = NULL; | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | int | ||
513 | mu_tls_stream_create (mu_stream_t *pstream, | ||
514 | mu_stream_t strin, mu_stream_t strout, | ||
515 | struct mu_tls_config const *conf, | ||
516 | enum mu_tls_type type, | ||
517 | int flags) | ||
717 | { | 518 | { |
718 | struct _mu_tls_stream *sp; | 519 | struct _mu_tls_stream *sp; |
719 | int rc; | 520 | int rc; |
720 | mu_stream_t stream; | 521 | mu_stream_t stream; |
522 | int session_type; | ||
523 | |||
524 | if (!pstream) | ||
525 | return MU_ERR_OUT_PTR_NULL; | ||
526 | if (!conf || !strin || !strout) | ||
527 | return EINVAL; | ||
528 | |||
529 | if (!mu_init_tls_libs ()) | ||
530 | return ENOSYS; | ||
531 | |||
532 | switch (mu_tls_config_check (conf, 1)) | ||
533 | { | ||
534 | case MU_TLS_CONFIG_OK: | ||
535 | case MU_TLS_CONFIG_NULL: | ||
536 | break; | ||
537 | case MU_TLS_CONFIG_UNSAFE: | ||
538 | return EACCES; | ||
539 | case MU_TLS_CONFIG_FAIL: | ||
540 | return ENOENT; | ||
541 | } | ||
542 | |||
543 | switch (type) | ||
544 | { | ||
545 | case MU_TLS_CLIENT: | ||
546 | session_type = GNUTLS_CLIENT; | ||
547 | break; | ||
548 | |||
549 | case MU_TLS_SERVER: | ||
550 | session_type = GNUTLS_SERVER; | ||
551 | break; | ||
552 | |||
553 | default: | ||
554 | return EINVAL; | ||
555 | } | ||
721 | 556 | ||
722 | sp = (struct _mu_tls_stream *) | 557 | sp = (struct _mu_tls_stream *) |
723 | _mu_stream_create (sizeof (*sp), MU_STREAM_RDWR); | 558 | _mu_stream_create (sizeof (*sp), MU_STREAM_RDWR); |
724 | if (!sp) | 559 | if (!sp) |
725 | return ENOMEM; | 560 | return ENOMEM; |
561 | sp->session_type = session_type; | ||
562 | sp->state = state_init; | ||
563 | sp->session = NULL; | ||
564 | sp->cred = NULL; | ||
726 | 565 | ||
566 | rc = copy_conf (&sp->conf, conf); | ||
567 | if (rc) | ||
568 | { | ||
569 | free (sp); | ||
570 | return rc; | ||
571 | } | ||
572 | |||
727 | sp->stream.read = _tls_read; | 573 | sp->stream.read = _tls_read; |
728 | sp->stream.write = _tls_write; | 574 | sp->stream.write = _tls_write; |
729 | sp->stream.flush = _tls_flush; | 575 | sp->stream.flush = _tls_flush; |
730 | sp->stream.open = openfn; | 576 | sp->stream.open = _tls_open; |
731 | sp->stream.close = _tls_close; | 577 | sp->stream.close = _tls_close; |
732 | sp->stream.done = _tls_done; | 578 | sp->stream.done = _tls_done; |
733 | sp->stream.ctl = _tls_ioctl; | 579 | sp->stream.ctl = _tls_ioctl; |
... | @@ -736,134 +582,43 @@ _mu_tls_stream_create (mu_stream_t *pstream, | ... | @@ -736,134 +582,43 @@ _mu_tls_stream_create (mu_stream_t *pstream, |
736 | 582 | ||
737 | mu_stream_set_buffer (strin, mu_buffer_none, 0); | 583 | mu_stream_set_buffer (strin, mu_buffer_none, 0); |
738 | mu_stream_set_buffer (strout, mu_buffer_none, 0); | 584 | mu_stream_set_buffer (strout, mu_buffer_none, 0); |
739 | rc = _mu_tls_io_stream_create (&sp->transport[0], strin, MU_STREAM_READ, sp); | ||
740 | if (rc) | ||
741 | { | ||
742 | free (sp); | ||
743 | return rc; | ||
744 | } | ||
745 | |||
746 | rc = _mu_tls_io_stream_create (&sp->transport[1], strout, MU_STREAM_WRITE, | ||
747 | sp); | ||
748 | if (rc) | ||
749 | { | ||
750 | free (sp); | ||
751 | free (sp->transport[0]); | ||
752 | return rc; | ||
753 | } | ||
754 | 585 | ||
755 | stream = (mu_stream_t) sp; | 586 | stream = (mu_stream_t) sp; |
587 | |||
588 | rc = mu_tls_io_stream_create (&sp->transport[0], strin, | ||
589 | MU_STREAM_READ, sp); | ||
590 | if (rc) | ||
591 | goto err; | ||
592 | |||
593 | rc = mu_tls_io_stream_create (&sp->transport[1], strout, | ||
594 | MU_STREAM_WRITE, sp); | ||
595 | if (rc) | ||
596 | goto err; | ||
597 | |||
756 | mu_stream_set_buffer (stream, mu_buffer_line, 0); | 598 | mu_stream_set_buffer (stream, mu_buffer_line, 0); |
757 | rc = mu_stream_open (stream); | 599 | rc = mu_stream_open (stream); |
758 | if (rc) | 600 | if (rc) |
759 | mu_stream_destroy (&stream); | 601 | goto err; |
760 | else | 602 | *pstream = stream; |
761 | *pstream = stream; | 603 | return 0; |
604 | |||
605 | err: | ||
606 | mu_stream_destroy (&stream); | ||
762 | return rc; | 607 | return rc; |
763 | } | 608 | } |
764 | 609 | ||
765 | int | ||
766 | mu_tls_server_stream_create (mu_stream_t *pstream, | ||
767 | mu_stream_t strin, mu_stream_t strout, int flags) | ||
768 | { | ||
769 | return _mu_tls_stream_create (pstream, | ||
770 | _tls_server_open, | ||
771 | strin, strout, flags); | ||
772 | } | ||
773 | |||
774 | int | 610 | int |
775 | mu_tls_client_stream_create (mu_stream_t *pstream, | 611 | mu_tls_client_stream_create (mu_stream_t *pstream, |
776 | mu_stream_t strin, mu_stream_t strout, int flags) | 612 | mu_stream_t strin, mu_stream_t strout, int flags) |
777 | { | 613 | { |
778 | return _mu_tls_stream_create (pstream, | 614 | struct mu_tls_config conf = { |
779 | _tls_client_open, | 615 | .cert_file = NULL, |
780 | strin, strout, flags); | 616 | .key_file = NULL, |
781 | } | 617 | .ca_file = NULL, |
782 | 618 | .priorities = NULL | |
783 | static int | 619 | }; |
784 | cb2_safety_checks (const char *name, void *data) | ||
785 | { | ||
786 | int defval; | ||
787 | |||
788 | if (data == &mu_tls_module_config.ssl_key_safety_checks) | ||
789 | defval = SSL_KEY_FILE_CHECKS; | ||
790 | else if (data == &mu_tls_module_config.ssl_cert_safety_checks) | ||
791 | defval = SSL_CERT_FILE_CHECKS; | ||
792 | else if (data == &mu_tls_module_config.ssl_cafile_safety_checks) | ||
793 | defval = SSL_CA_FILE_CHECKS; | ||
794 | else | ||
795 | { | ||
796 | mu_error (_("INTERNAL ERROR at %s:%d: unknown default value?"), | ||
797 | __FILE__, __LINE__); | ||
798 | defval = MU_FILE_SAFETY_ALL; | ||
799 | } | ||
800 | if (mu_file_safety_compose (data, name, defval)) | ||
801 | mu_error (_("unknown keyword: %s"), name); | ||
802 | return 0; | ||
803 | } | ||
804 | 620 | ||
805 | static int | 621 | return mu_tls_stream_create (pstream, strin, strout, &conf, MU_TLS_CLIENT, |
806 | cb_safety_checks (void *data, mu_config_value_t *arg) | 622 | flags); |
807 | { | ||
808 | return mu_cfg_string_value_cb (arg, cb2_safety_checks, data); | ||
809 | } | 623 | } |
810 | 624 | ||
811 | static struct mu_cfg_param mu_tls_param[] = { | ||
812 | { "enable", mu_c_bool, &mu_tls_module_config.enable, 0, NULL, | ||
813 | N_("Enable TLS encryption.") }, | ||
814 | { "ssl-cert", mu_c_string, &mu_tls_module_config.ssl_cert, 0, NULL, | ||
815 | N_("Specify SSL certificate file."), | ||
816 | N_("file") }, | ||
817 | { "ssl-key", mu_c_string, &mu_tls_module_config.ssl_key, 0, NULL, | ||
818 | N_("Specify SSL certificate key file."), | ||
819 | N_("file") }, | ||
820 | { "ssl-cafile", mu_c_string, &mu_tls_module_config.ssl_cafile, 0, NULL, | ||
821 | N_("Specify trusted CAs file."), | ||
822 | N_("file") }, | ||
823 | { "ssl-priorities", mu_c_string, &mu_tls_module_config.priorities, 0, NULL, | ||
824 | N_("Set the priorities to use on the ciphers, key exchange methods, " | ||
825 | "macs and compression methods."), | ||
826 | NULL }, | ||
827 | { "key-file-safety-checks", mu_cfg_callback, | ||
828 | &mu_tls_module_config.ssl_key_safety_checks, 0, | ||
829 | cb_safety_checks, | ||
830 | N_("Configure safety checks for SSL key file. Argument is a list or " | ||
831 | "sequence of check names optionally prefixed with '+' to enable or " | ||
832 | "'-' to disable the corresponding check. Valid check names are:\n" | ||
833 | "\n" | ||
834 | " none disable all checks\n" | ||
835 | " all enable all checks\n" | ||
836 | " gwrfil forbid group writable files\n" | ||
837 | " awrfil forbid world writable files\n" | ||
838 | " grdfil forbid group readable files\n" | ||
839 | " ardfil forbid world writable files\n" | ||
840 | " linkwrdir forbid symbolic links in group or world writable directories\n" | ||
841 | " gwrdir forbid files in group writable directories\n" | ||
842 | " awrdir forbid files in world writable directories\n"), | ||
843 | N_("arg: list") }, | ||
844 | { "cert-file-safety-checks", mu_cfg_callback, | ||
845 | &mu_tls_module_config.ssl_cert_safety_checks, 0, | ||
846 | cb_safety_checks, | ||
847 | N_("Configure safety checks for SSL certificate. See above for a description of <arg>."), | ||
848 | N_("arg: list") }, | ||
849 | { "ca-file-safety-checks", mu_cfg_callback, | ||
850 | &mu_tls_module_config.ssl_cafile_safety_checks, 0, | ||
851 | cb_safety_checks, | ||
852 | N_("Configure safety checks for SSL certificate authority file. See above for a description of <arg>."), | ||
853 | N_("arg: list") }, | ||
854 | { NULL } | ||
855 | }; | ||
856 | |||
857 | struct mu_auth_module mu_auth_tls_module = { | ||
858 | .name = "tls", | ||
859 | .cfg = mu_tls_param | ||
860 | }; | ||
861 | |||
862 | #else | ||
863 | struct mu_auth_module mu_auth_tls_module = { | ||
864 | .name = "tls" | ||
865 | }; | ||
866 | #endif /* WITH_TLS */ | ||
867 | |||
868 | /* EOF */ | ||
869 | ... | ... |
libmu_auth/tlsconf.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2003-2004, 2007-2012, 2014-2017 Free Software | ||
3 | Foundation, Inc. | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 3 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General | ||
16 | Public License along with this library. If not, see | ||
17 | <http://www.gnu.org/licenses/>. */ | ||
18 | |||
19 | #if HAVE_CONFIG_H | ||
20 | # include <config.h> | ||
21 | #endif | ||
22 | #include <stdlib.h> | ||
23 | #include <mailutils/tls.h> | ||
24 | #include <mailutils/nls.h> | ||
25 | #include <mailutils/error.h> | ||
26 | #include <mailutils/errno.h> | ||
27 | #include <mailutils/mu_auth.h> | ||
28 | |||
29 | |||
30 | struct safety_check_closure | ||
31 | { | ||
32 | int defval; | ||
33 | int *data; | ||
34 | }; | ||
35 | |||
36 | static int | ||
37 | cb_safety_checks (const char *name, void *data) | ||
38 | { | ||
39 | struct safety_check_closure *cp = data; | ||
40 | |||
41 | if (mu_file_safety_compose (cp->data, name, cp->defval)) | ||
42 | mu_error (_("unknown keyword: %s"), name); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int | ||
47 | cb_cert_safety_checks (void *data, mu_config_value_t *arg) | ||
48 | { | ||
49 | struct safety_check_closure clos; | ||
50 | clos.defval = MU_TLS_CERT_FILE_CHECKS; | ||
51 | clos.data = data; | ||
52 | return mu_cfg_string_value_cb (arg, cb_safety_checks, &clos); | ||
53 | } | ||
54 | |||
55 | static int | ||
56 | cb_key_safety_checks (void *data, mu_config_value_t *arg) | ||
57 | { | ||
58 | struct safety_check_closure clos; | ||
59 | clos.defval = MU_TLS_KEY_FILE_CHECKS; | ||
60 | clos.data = data; | ||
61 | return mu_cfg_string_value_cb (arg, cb_safety_checks, &clos); | ||
62 | } | ||
63 | |||
64 | static int | ||
65 | cb_ca_safety_checks (void *data, mu_config_value_t *arg) | ||
66 | { | ||
67 | struct safety_check_closure clos; | ||
68 | clos.defval = MU_TLS_CA_FILE_CHECKS; | ||
69 | clos.data = data; | ||
70 | return mu_cfg_string_value_cb (arg, cb_safety_checks, &clos); | ||
71 | } | ||
72 | |||
73 | static struct mu_cfg_param mu_tls_global_param[] = { | ||
74 | { "key-file", mu_cfg_callback, | ||
75 | &mu_tls_key_file_checks, 0, | ||
76 | cb_key_safety_checks, | ||
77 | N_("Configure safety checks for SSL key file. Argument is a list or " | ||
78 | "sequence of check names optionally prefixed with '+' to enable or " | ||
79 | "'-' to disable the corresponding check. Valid check names are:\n" | ||
80 | "\n" | ||
81 | " none disable all checks\n" | ||
82 | " all enable all checks\n" | ||
83 | " gwrfil forbid group writable files\n" | ||
84 | " awrfil forbid world writable files\n" | ||
85 | " grdfil forbid group readable files\n" | ||
86 | " ardfil forbid world writable files\n" | ||
87 | " linkwrdir forbid symbolic links in group or world writable directories\n" | ||
88 | " gwrdir forbid files in group writable directories\n" | ||
89 | " awrdir forbid files in world writable directories\n"), | ||
90 | N_("arg: list") }, | ||
91 | { "cert-file", mu_cfg_callback, | ||
92 | &mu_tls_cert_file_checks, 0, | ||
93 | cb_cert_safety_checks, | ||
94 | N_("Configure safety checks for SSL certificate. See above for a description of <arg>."), | ||
95 | N_("arg: list") }, | ||
96 | { "ca-file", mu_cfg_callback, | ||
97 | &mu_tls_ca_file_checks, 0, | ||
98 | cb_ca_safety_checks, | ||
99 | N_("Configure safety checks for SSL certificate authority file. See above for a description of <arg>."), | ||
100 | N_("arg: list") }, | ||
101 | { NULL } | ||
102 | }; | ||
103 | |||
104 | static struct mu_cfg_param tls_canned_param[] = { | ||
105 | { "ssl-certificate-file", mu_c_string, | ||
106 | NULL, mu_offsetof(struct mu_tls_config, cert_file), NULL, | ||
107 | N_("Specify SSL certificate file."), | ||
108 | N_("file") }, | ||
109 | { "ssl-key-file", mu_c_string, | ||
110 | NULL, mu_offsetof(struct mu_tls_config, key_file), NULL, | ||
111 | N_("Specify SSL certificate key file."), | ||
112 | N_("file") }, | ||
113 | { "ssl-ca-file", mu_c_string, | ||
114 | NULL, mu_offsetof(struct mu_tls_config, ca_file), NULL, | ||
115 | N_("Specify trusted CAs file."), | ||
116 | N_("file") }, | ||
117 | { "ssl-priorities", mu_c_string, | ||
118 | NULL, mu_offsetof(struct mu_tls_config, priorities), NULL, | ||
119 | N_("Set the priorities to use on the ciphers, key exchange methods, " | ||
120 | "macs and compression methods."), | ||
121 | NULL }, | ||
122 | { NULL } | ||
123 | }; | ||
124 | |||
125 | void | ||
126 | mu_tls_cfg_init (void) | ||
127 | { | ||
128 | struct mu_cfg_section *section; | ||
129 | |||
130 | if (mu_create_canned_section ("tls", §ion)) | ||
131 | abort (); | ||
132 | section->docstring = N_("Configure TLS"); | ||
133 | section->label = NULL; | ||
134 | mu_cfg_section_add_params (section, tls_canned_param); | ||
135 | } | ||
136 | |||
137 | struct mu_auth_module mu_auth_tls_module = { | ||
138 | .name = "tls-file-checks", | ||
139 | .cfg = mu_tls_global_param, | ||
140 | }; |
libmu_auth/tlsiostr.c
0 → 100644
1 | /* TLS I/O streams */ | ||
2 | |||
3 | #if HAVE_CONFIG_H | ||
4 | # include <config.h> | ||
5 | #endif | ||
6 | #include <stdlib.h> | ||
7 | #include <gnutls/gnutls.h> | ||
8 | #include <mailutils/stream.h> | ||
9 | #include <mailutils/errno.h> | ||
10 | #include <mailutils/property.h> | ||
11 | #include <mailutils/sys/tls-stream.h> | ||
12 | |||
13 | static int | ||
14 | _tls_io_close (mu_stream_t stream) | ||
15 | { | ||
16 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
17 | |||
18 | return mu_stream_close (sp->transport); | ||
19 | } | ||
20 | |||
21 | static void | ||
22 | _tls_io_done (struct _mu_stream *stream) | ||
23 | { | ||
24 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
25 | mu_stream_unref (sp->transport); | ||
26 | } | ||
27 | |||
28 | static int | ||
29 | _tls_io_flush (struct _mu_stream *stream) | ||
30 | { | ||
31 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
32 | return mu_stream_flush (sp->transport); | ||
33 | } | ||
34 | |||
35 | static int | ||
36 | _tls_io_read (struct _mu_stream *stream, char *buf, size_t bufsize, | ||
37 | size_t *pnread) | ||
38 | { | ||
39 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
40 | int rc; | ||
41 | |||
42 | if (sp->up->state != state_open) | ||
43 | return EINVAL; | ||
44 | rc = gnutls_record_recv (sp->up->session, buf, bufsize); | ||
45 | if (rc >= 0) | ||
46 | { | ||
47 | *pnread = rc; | ||
48 | return 0; | ||
49 | } | ||
50 | sp->up->tls_err = rc; | ||
51 | return EIO; | ||
52 | } | ||
53 | |||
54 | static int | ||
55 | _tls_io_write (struct _mu_stream *stream, const char *buf, size_t bufsize, | ||
56 | size_t *pnwrite) | ||
57 | { | ||
58 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
59 | int rc; | ||
60 | |||
61 | if (sp->up->state != state_open) | ||
62 | return EINVAL; | ||
63 | |||
64 | /* gnutls_record_send() docs say: | ||
65 | If the EINTR is returned by the internal push function (write()) | ||
66 | then GNUTLS_E_INTERRUPTED, will be returned. If GNUTLS_E_INTERRUPTED or | ||
67 | GNUTLS_E_AGAIN is returned you must call this function again, with the | ||
68 | same parameters. Otherwise the write operation will be | ||
69 | corrupted and the connection will be terminated. */ | ||
70 | |||
71 | do | ||
72 | rc = gnutls_record_send (sp->up->session, buf, bufsize); | ||
73 | while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN); | ||
74 | |||
75 | if (rc < 0) | ||
76 | { | ||
77 | sp->up->tls_err = rc; | ||
78 | return EIO; | ||
79 | } | ||
80 | |||
81 | *pnwrite = rc; | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int | ||
87 | _tls_rd_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp) | ||
88 | { | ||
89 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
90 | int rc = EINVAL; | ||
91 | |||
92 | if (*pflags == MU_STREAM_READY_RD) | ||
93 | rc = mu_stream_wait (sp->transport, pflags, tvp); | ||
94 | return rc; | ||
95 | } | ||
96 | |||
97 | static int | ||
98 | _tls_wr_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp) | ||
99 | { | ||
100 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
101 | int rc = EINVAL; | ||
102 | |||
103 | if (*pflags == MU_STREAM_READY_WR) | ||
104 | rc = mu_stream_wait (sp->transport, pflags, tvp); | ||
105 | return rc; | ||
106 | } | ||
107 | |||
108 | static int | ||
109 | get_cipher_info (gnutls_session_t session, mu_property_t *pprop) | ||
110 | { | ||
111 | mu_property_t prop; | ||
112 | const char *s; | ||
113 | int rc; | ||
114 | |||
115 | if (!pprop) | ||
116 | return EINVAL; | ||
117 | |||
118 | rc = mu_property_create_init (&prop, mu_assoc_property_init, NULL); | ||
119 | if (rc) | ||
120 | return rc; | ||
121 | |||
122 | s = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); | ||
123 | mu_property_set_value (prop, "protocol", s, 1); | ||
124 | |||
125 | s = gnutls_cipher_get_name (gnutls_cipher_get (session)); | ||
126 | mu_property_set_value (prop, "cipher", s, 1); | ||
127 | |||
128 | s = gnutls_mac_get_name (gnutls_mac_get (session)); | ||
129 | mu_property_set_value (prop, "mac", s, 1); | ||
130 | |||
131 | *pprop = prop; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int | ||
137 | _tls_io_ioctl (struct _mu_stream *stream, int code, int opcode, void *arg) | ||
138 | { | ||
139 | struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; | ||
140 | |||
141 | switch (code) | ||
142 | { | ||
143 | case MU_IOCTL_TRANSPORT: | ||
144 | if (!arg) | ||
145 | return EINVAL; | ||
146 | else | ||
147 | { | ||
148 | mu_transport_t *ptrans = arg; | ||
149 | switch (opcode) | ||
150 | { | ||
151 | case MU_IOCTL_OP_GET: | ||
152 | ptrans[0] = (mu_transport_t) sp->transport; | ||
153 | ptrans[1] = NULL; | ||
154 | break; | ||
155 | |||
156 | case MU_IOCTL_OP_SET: | ||
157 | return ENOSYS; | ||
158 | |||
159 | default: | ||
160 | return EINVAL; | ||
161 | } | ||
162 | } | ||
163 | break; | ||
164 | |||
165 | case MU_IOCTL_TLSSTREAM: | ||
166 | switch (opcode) | ||
167 | { | ||
168 | case MU_IOCTL_TLS_GET_CIPHER_INFO: | ||
169 | return get_cipher_info (sp->up->session, arg); | ||
170 | |||
171 | default: | ||
172 | return EINVAL; | ||
173 | } | ||
174 | break; | ||
175 | |||
176 | default: | ||
177 | return ENOSYS; | ||
178 | } | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | int | ||
183 | mu_tls_io_stream_create (mu_stream_t *pstream, | ||
184 | mu_stream_t transport, int flags, | ||
185 | struct _mu_tls_stream *master) | ||
186 | { | ||
187 | struct _mu_tls_io_stream *sp; | ||
188 | |||
189 | sp = (struct _mu_tls_io_stream *) | ||
190 | _mu_stream_create (sizeof (*sp), (flags & MU_STREAM_RDWR) | _MU_STR_OPEN); | ||
191 | if (!sp) | ||
192 | return ENOMEM; | ||
193 | |||
194 | if (flags & MU_STREAM_READ) | ||
195 | { | ||
196 | sp->stream.read = _tls_io_read; | ||
197 | sp->stream.wait = _tls_rd_wait; | ||
198 | mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_full, 0); | ||
199 | } | ||
200 | else | ||
201 | { | ||
202 | sp->stream.write = _tls_io_write; | ||
203 | sp->stream.wait = _tls_wr_wait; | ||
204 | mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 0); | ||
205 | } | ||
206 | sp->stream.flush = _tls_io_flush; | ||
207 | sp->stream.close = _tls_io_close; | ||
208 | sp->stream.done = _tls_io_done; | ||
209 | sp->stream.ctl = _tls_io_ioctl; | ||
210 | |||
211 | mu_stream_ref (transport); | ||
212 | sp->transport = transport; | ||
213 | sp->up = master; | ||
214 | *pstream = (mu_stream_t) sp; | ||
215 | return 0; | ||
216 | } |
libmu_auth/tlsvar.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2003-2004, 2007-2012, 2014-2017 Free Software | ||
3 | Foundation, Inc. | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 3 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General | ||
16 | Public License along with this library. If not, see | ||
17 | <http://www.gnu.org/licenses/>. */ | ||
18 | |||
19 | #if HAVE_CONFIG_H | ||
20 | # include <config.h> | ||
21 | #endif | ||
22 | |||
23 | #include <mailutils/tls.h> | ||
24 | #include <mailutils/errno.h> | ||
25 | |||
26 | int mu_tls_enable = 0; | ||
27 | int mu_tls_cert_file_checks = MU_TLS_CERT_FILE_CHECKS; | ||
28 | int mu_tls_key_file_checks = MU_TLS_KEY_FILE_CHECKS; | ||
29 | int mu_tls_ca_file_checks = MU_TLS_CA_FILE_CHECKS; | ||
30 | |||
31 | static int | ||
32 | check_err(int rc) | ||
33 | { | ||
34 | switch (rc) | ||
35 | { | ||
36 | case MU_ERR_PERM_OWNER_MISMATCH: | ||
37 | case MU_ERR_PERM_GROUP_WRITABLE: | ||
38 | case MU_ERR_PERM_WORLD_WRITABLE: | ||
39 | case MU_ERR_PERM_GROUP_READABLE: | ||
40 | case MU_ERR_PERM_WORLD_READABLE: | ||
41 | case MU_ERR_PERM_LINKED_WRDIR: | ||
42 | case MU_ERR_PERM_DIR_IWGRP: | ||
43 | case MU_ERR_PERM_DIR_IWOTH: | ||
44 | return MU_TLS_CONFIG_UNSAFE; | ||
45 | default: | ||
46 | return MU_TLS_CONFIG_FAIL; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | int | ||
51 | mu_tls_config_check (struct mu_tls_config const *conf, int verbose) | ||
52 | { | ||
53 | int rc; | ||
54 | int res = MU_TLS_CONFIG_NULL; | ||
55 | |||
56 | if (conf->cert_file) | ||
57 | { | ||
58 | rc = mu_file_safety_check (conf->cert_file, mu_tls_cert_file_checks, | ||
59 | -1, NULL); | ||
60 | if (rc) | ||
61 | { | ||
62 | if (verbose) | ||
63 | mu_error ("%s: %s", conf->cert_file, mu_strerror (rc)); | ||
64 | return check_err (rc); | ||
65 | } | ||
66 | res = MU_TLS_CONFIG_OK; | ||
67 | } | ||
68 | |||
69 | if (conf->key_file) | ||
70 | { | ||
71 | rc = mu_file_safety_check (conf->key_file, mu_tls_key_file_checks, | ||
72 | -1, NULL); | ||
73 | if (rc) | ||
74 | { | ||
75 | if (verbose) | ||
76 | mu_error ("%s: %s", conf->key_file, mu_strerror (rc)); | ||
77 | return check_err (rc); | ||
78 | } | ||
79 | res = MU_TLS_CONFIG_OK; | ||
80 | } | ||
81 | |||
82 | if (conf->ca_file) | ||
83 | { | ||
84 | rc = mu_file_safety_check (conf->ca_file, mu_tls_ca_file_checks, | ||
85 | -1, NULL); | ||
86 | if (rc) | ||
87 | { | ||
88 | if (verbose) | ||
89 | mu_error ("%s: %s", conf->ca_file, mu_strerror (rc)); | ||
90 | return check_err (rc); | ||
91 | } | ||
92 | res = MU_TLS_CONFIG_OK; | ||
93 | } | ||
94 | |||
95 | if (conf->priorities) | ||
96 | res = MU_TLS_CONFIG_OK; | ||
97 | |||
98 | return res; | ||
99 | |||
100 | } | ||
101 |
... | @@ -104,17 +104,20 @@ capa_implementation (const char *name, struct pop3d_session *session) | ... | @@ -104,17 +104,20 @@ capa_implementation (const char *name, struct pop3d_session *session) |
104 | pop3d_outf ("%s %s\n", name, PACKAGE_STRING); | 104 | pop3d_outf ("%s %s\n", name, PACKAGE_STRING); |
105 | } | 105 | } |
106 | 106 | ||
107 | #ifdef WITH_TLS | ||
108 | static void | 107 | static void |
109 | capa_stls (const char *name, struct pop3d_session *session) | 108 | capa_stls (const char *name, struct pop3d_session *session) |
110 | { | 109 | { |
111 | if ((session->tls == tls_ondemand || session->tls == tls_required) | 110 | switch (session->tls_mode) |
112 | && tls_available && tls_done == 0) | 111 | { |
113 | pop3d_outf ("%s\n", name); | 112 | case tls_ondemand: |
113 | case tls_required: | ||
114 | pop3d_outf ("%s\n", name); | ||
115 | break; | ||
116 | |||
117 | default: | ||
118 | break; | ||
119 | } | ||
114 | } | 120 | } |
115 | #else | ||
116 | # define capa_stls NULL | ||
117 | #endif /* WITH_TLS */ | ||
118 | 121 | ||
119 | static void | 122 | static void |
120 | capa_user (const char *name, struct pop3d_session *session) | 123 | capa_user (const char *name, struct pop3d_session *session) | ... | ... |
... | @@ -16,13 +16,12 @@ | ... | @@ -16,13 +16,12 @@ |
16 | 16 | ||
17 | #include "pop3d.h" | 17 | #include "pop3d.h" |
18 | 18 | ||
19 | struct mu_tls_config global_tls_conf; | ||
20 | |||
19 | static struct pop3d_command command_table[] = { | 21 | static struct pop3d_command command_table[] = { |
20 | #ifdef WITH_TLS | ||
21 | { "STLS", pop3d_stls }, | 22 | { "STLS", pop3d_stls }, |
22 | # define COMMAND_TABLE_HEAD 1 | 23 | #define COMMAND_TABLE_STLS 0 |
23 | #else | 24 | #define COMMAND_TABLE_PLAIN 1 |
24 | # define COMMAND_TABLE_HEAD 0 | ||
25 | #endif | ||
26 | { "RETR", pop3d_retr }, | 25 | { "RETR", pop3d_retr }, |
27 | { "DELE", pop3d_dele }, | 26 | { "DELE", pop3d_dele }, |
28 | { "USER", pop3d_user }, | 27 | { "USER", pop3d_user }, |
... | @@ -39,8 +38,7 @@ static struct pop3d_command command_table[] = { | ... | @@ -39,8 +38,7 @@ static struct pop3d_command command_table[] = { |
39 | { NULL } | 38 | { NULL } |
40 | }; | 39 | }; |
41 | 40 | ||
42 | static struct pop3d_command *command_table_head = | 41 | static struct pop3d_command *command_table_head; |
43 | command_table + COMMAND_TABLE_HEAD; | ||
44 | 42 | ||
45 | pop3d_command_handler_t | 43 | pop3d_command_handler_t |
46 | pop3d_find_command (const char *name) | 44 | pop3d_find_command (const char *name) |
... | @@ -54,57 +52,130 @@ pop3d_find_command (const char *name) | ... | @@ -54,57 +52,130 @@ pop3d_find_command (const char *name) |
54 | return p->handler; | 52 | return p->handler; |
55 | } | 53 | } |
56 | 54 | ||
57 | #ifdef WITH_TLS | 55 | int |
58 | void | 56 | stls_preflight (mu_m_server_t msrv) |
59 | enable_stls () | ||
60 | { | 57 | { |
61 | command_table_head = command_table; | 58 | mu_list_t srvlist; |
62 | } | 59 | mu_iterator_t itr; |
63 | #endif | 60 | int errors = 0; |
61 | int tls_ok = mu_init_tls_libs (); | ||
62 | int tls_requested = 0; | ||
63 | int global_conf_status = 0; | ||
64 | 64 | ||
65 | struct error_table | 65 | if (global_tls_conf.cert_file) |
66 | { | 66 | global_conf_status = mu_tls_config_check (&global_tls_conf, 1); |
67 | int code; | 67 | else |
68 | const char *text; | 68 | global_conf_status = MU_TLS_CONFIG_NULL; |
69 | }; | 69 | |
70 | mu_m_server_get_srvlist (msrv, &srvlist); | ||
71 | mu_list_get_iterator (srvlist, &itr); | ||
72 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) | ||
73 | { | ||
74 | mu_ip_server_t ipsrv; | ||
75 | struct pop3d_srv_config *cfg; | ||
76 | mu_iterator_current (itr, (void**) &ipsrv); | ||
77 | cfg = mu_ip_server_get_data (ipsrv); | ||
78 | switch (cfg->tls_mode) | ||
79 | { | ||
80 | case tls_unspecified: | ||
81 | if (cfg->tls_conf.cert_file) | ||
82 | { | ||
83 | cfg->tls_mode = tls_ondemand; | ||
84 | break; | ||
85 | } | ||
86 | else | ||
87 | cfg->tls_mode = tls_no; | ||
88 | /* fall through */ | ||
89 | case tls_no: | ||
90 | continue; | ||
91 | |||
92 | default: | ||
93 | break; | ||
94 | } | ||
95 | |||
96 | switch (mu_tls_config_check (&cfg->tls_conf, 1)) | ||
97 | { | ||
98 | case MU_TLS_CONFIG_OK: | ||
99 | if (!cfg->tls_conf.cert_file) | ||
100 | { | ||
101 | mu_error (_("server %s: no certificate set"), | ||
102 | mu_ip_server_addrstr (ipsrv)); | ||
103 | errors = 1; | ||
104 | } | ||
105 | break; | ||
106 | |||
107 | case MU_TLS_CONFIG_NULL: | ||
108 | if (global_conf_status != MU_TLS_CONFIG_NULL) | ||
109 | { | ||
110 | cfg->tls_conf = global_tls_conf; | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | mu_error (_("server %s: no certificate set"), | ||
115 | mu_ip_server_addrstr (ipsrv)); | ||
116 | errors = 1; | ||
117 | } | ||
118 | break; | ||
119 | |||
120 | default: | ||
121 | mu_error (_("server %s: TLS configuration failed"), | ||
122 | mu_ip_server_addrstr (ipsrv)); | ||
123 | errors = 1; | ||
124 | } | ||
125 | |||
126 | tls_requested = 1; | ||
127 | } | ||
128 | mu_iterator_destroy (&itr); | ||
129 | |||
130 | if (tls_requested && !tls_ok) | ||
131 | { | ||
132 | mu_error (_("TLS is not configured, but requested in the " | ||
133 | "configuration")); | ||
134 | errors = 1; | ||
135 | } | ||
136 | |||
137 | if (errors) | ||
138 | return 1; | ||
139 | |||
140 | if (tls_requested) | ||
141 | command_table_head = command_table + COMMAND_TABLE_STLS; | ||
142 | else | ||
143 | command_table_head = command_table + COMMAND_TABLE_PLAIN; | ||
144 | |||
145 | return 0; | ||
146 | } | ||
70 | 147 | ||
71 | static struct error_table error_table[] = { | 148 | static char *error_table[] = { |
72 | { ERR_WRONG_STATE, "Incorrect state" }, | 149 | [ERR_WRONG_STATE] = "Incorrect state", |
73 | { ERR_BAD_ARGS, "Invalid arguments" }, | 150 | [ERR_BAD_ARGS] = "Invalid arguments", |
74 | { ERR_BAD_LOGIN, "[AUTH] Bad login" }, | 151 | [ERR_BAD_LOGIN] = "[AUTH] Bad login", |
75 | { ERR_NO_MESG, "No such message" }, | 152 | [ERR_NO_MESG] = "No such message", |
76 | { ERR_MESG_DELE, "Message has been deleted" }, | 153 | [ERR_MESG_DELE] = "Message has been deleted", |
77 | { ERR_NOT_IMPL, "Not implemented" }, | 154 | [ERR_NOT_IMPL] = "Not implemented", |
78 | { ERR_BAD_CMD, "Invalid command" }, | 155 | [ERR_BAD_CMD] = "Invalid command", |
79 | { ERR_MBOX_LOCK, "[IN-USE] Mailbox in use" }, | 156 | [ERR_MBOX_LOCK] = "[IN-USE] Mailbox in use", |
80 | { ERR_TOO_LONG, "Argument too long" }, | 157 | [ERR_TOO_LONG] = "Argument too long", |
81 | { ERR_NO_MEM, "Out of memory, quitting" }, | 158 | [ERR_NO_MEM] = "Out of memory] =quitting", |
82 | { ERR_SIGNAL, "Quitting on signal" }, | 159 | [ERR_SIGNAL] = "Quitting on signal", |
83 | { ERR_FILE, "Some deleted messages not removed" }, | 160 | [ERR_FILE] = "Some deleted messages not removed", |
84 | { ERR_NO_IFILE, "No input stream" }, | 161 | [ERR_NO_IFILE] = "No input stream", |
85 | { ERR_NO_OFILE, "No output stream" }, | 162 | [ERR_NO_OFILE] = "No output stream", |
86 | { ERR_IO, "I/O error" }, | 163 | [ERR_IO] = "I/O error", |
87 | { ERR_PROTO, "Remote protocol error" }, | 164 | [ERR_PROTO] = "Remote protocol error", |
88 | { ERR_TIMEOUT, "Session timed out" }, | 165 | [ERR_TIMEOUT] = "Session timed out", |
89 | { ERR_UNKNOWN, "Unknown error" }, | 166 | [ERR_UNKNOWN] = "Unknown error", |
90 | { ERR_MBOX_SYNC, "Mailbox was updated by other process" }, | 167 | [ERR_MBOX_SYNC] = "Mailbox was updated by other process", |
91 | #ifdef WITH_TLS | 168 | [ERR_TLS_IO] = "TLS I/O error", |
92 | { ERR_TLS_ACTIVE, "Command not permitted when TLS active" }, | 169 | [ERR_LOGIN_DELAY] = |
93 | #endif /* WITH_TLS */ | 170 | "[LOGIN-DELAY] Attempt to log in within the minimum login delay interval", |
94 | { ERR_TLS_IO, "TLS I/O error" }, | 171 | [ERR_TERMINATE] = "Terminating on request", |
95 | { ERR_LOGIN_DELAY, | 172 | [ERR_SYS_LOGIN] = "[SYS/PERM] Cannot authenticate", |
96 | "[LOGIN-DELAY] Attempt to log in within the minimum login delay interval" }, | ||
97 | { ERR_TERMINATE, "Terminating on request" }, | ||
98 | { ERR_SYS_LOGIN, "[SYS/PERM] Cannot authenticate" }, | ||
99 | { 0 } | ||
100 | }; | 173 | }; |
101 | 174 | ||
102 | const char * | 175 | const char * |
103 | pop3d_error_string (int code) | 176 | pop3d_error_string (int code) |
104 | { | 177 | { |
105 | struct error_table *ep; | 178 | if (code >= 0 && code < MU_ARRAY_SIZE (error_table) && error_table[code]) |
106 | for (ep = error_table; ep->code != 0; ep++) | 179 | return error_table[code]; |
107 | if (ep->code == code) | ||
108 | return ep->text; | ||
109 | return "unknown error"; | 180 | return "unknown error"; |
110 | } | 181 | } | ... | ... |
... | @@ -158,7 +158,7 @@ log_cipher (mu_stream_t stream) | ... | @@ -158,7 +158,7 @@ log_cipher (mu_stream_t stream) |
158 | } | 158 | } |
159 | 159 | ||
160 | void | 160 | void |
161 | pop3d_setio (int ifd, int ofd, int tls) | 161 | pop3d_setio (int ifd, int ofd, struct mu_tls_config *tls_conf) |
162 | { | 162 | { |
163 | mu_stream_t str, istream, ostream; | 163 | mu_stream_t str, istream, ostream; |
164 | 164 | ||
... | @@ -175,10 +175,12 @@ pop3d_setio (int ifd, int ofd, int tls) | ... | @@ -175,10 +175,12 @@ pop3d_setio (int ifd, int ofd, int tls) |
175 | pop3d_abquit (ERR_NO_OFILE); | 175 | pop3d_abquit (ERR_NO_OFILE); |
176 | 176 | ||
177 | /* Combine the two streams into an I/O one. */ | 177 | /* Combine the two streams into an I/O one. */ |
178 | #ifdef WITH_TLS | 178 | if (tls_conf) |
179 | if (tls) | ||
180 | { | 179 | { |
181 | int rc = mu_tls_server_stream_create (&str, istream, ostream, 0); | 180 | int rc = mu_tls_stream_create (&str, istream, ostream, |
181 | tls_conf, | ||
182 | MU_TLS_SERVER, | ||
183 | 0); | ||
182 | if (rc) | 184 | if (rc) |
183 | { | 185 | { |
184 | mu_stream_unref (istream); | 186 | mu_stream_unref (istream); |
... | @@ -186,12 +188,9 @@ pop3d_setio (int ifd, int ofd, int tls) | ... | @@ -186,12 +188,9 @@ pop3d_setio (int ifd, int ofd, int tls) |
186 | mu_error (_("failed to create TLS stream: %s"), mu_strerror (rc)); | 188 | mu_error (_("failed to create TLS stream: %s"), mu_strerror (rc)); |
187 | pop3d_abquit (ERR_FILE); | 189 | pop3d_abquit (ERR_FILE); |
188 | } | 190 | } |
189 | tls_done = 1; | ||
190 | log_cipher (str); | 191 | log_cipher (str); |
191 | } | 192 | } |
192 | else | 193 | else if (mu_iostream_create (&str, istream, ostream)) |
193 | #endif | ||
194 | if (mu_iostream_create (&str, istream, ostream)) | ||
195 | pop3d_abquit (ERR_FILE); | 194 | pop3d_abquit (ERR_FILE); |
196 | 195 | ||
197 | /* Convert all writes to CRLF form. | 196 | /* Convert all writes to CRLF form. |
... | @@ -228,9 +227,8 @@ pop3d_setio (int ifd, int ofd, int tls) | ... | @@ -228,9 +227,8 @@ pop3d_setio (int ifd, int ofd, int tls) |
228 | } | 227 | } |
229 | } | 228 | } |
230 | 229 | ||
231 | #ifdef WITH_TLS | ||
232 | int | 230 | int |
233 | pop3d_init_tls_server () | 231 | pop3d_init_tls_server (struct mu_tls_config *tls_conf) |
234 | { | 232 | { |
235 | mu_stream_t tlsstream, stream[2]; | 233 | mu_stream_t tlsstream, stream[2]; |
236 | int rc; | 234 | int rc; |
... | @@ -243,7 +241,10 @@ pop3d_init_tls_server () | ... | @@ -243,7 +241,10 @@ pop3d_init_tls_server () |
243 | return 1; | 241 | return 1; |
244 | } | 242 | } |
245 | 243 | ||
246 | rc = mu_tls_server_stream_create (&tlsstream, stream[0], stream[1], 0); | 244 | rc = mu_tls_stream_create (&tlsstream, stream[0], stream[1], |
245 | tls_conf, | ||
246 | MU_TLS_SERVER, | ||
247 | 0); | ||
247 | mu_stream_unref (stream[0]); | 248 | mu_stream_unref (stream[0]); |
248 | mu_stream_unref (stream[1]); | 249 | mu_stream_unref (stream[1]); |
249 | if (rc) | 250 | if (rc) |
... | @@ -263,7 +264,6 @@ pop3d_init_tls_server () | ... | @@ -263,7 +264,6 @@ pop3d_init_tls_server () |
263 | } | 264 | } |
264 | return 0; | 265 | return 0; |
265 | } | 266 | } |
266 | #endif | ||
267 | 267 | ||
268 | void | 268 | void |
269 | pop3d_bye () | 269 | pop3d_bye () | ... | ... |
... | @@ -37,15 +37,6 @@ int apop_database_safety = MU_FILE_SAFETY_ALL; | ... | @@ -37,15 +37,6 @@ int apop_database_safety = MU_FILE_SAFETY_ALL; |
37 | uid_t apop_database_owner; | 37 | uid_t apop_database_owner; |
38 | int apop_database_owner_set; | 38 | int apop_database_owner_set; |
39 | 39 | ||
40 | enum tls_mode tls_mode; | ||
41 | |||
42 | #ifdef WITH_TLS | ||
43 | int tls_available; | ||
44 | int tls_done; | ||
45 | #else | ||
46 | # define tls_available 0 | ||
47 | #endif /* WITH_TLS */ | ||
48 | |||
49 | int initial_state = AUTHORIZATION; | 40 | int initial_state = AUTHORIZATION; |
50 | 41 | ||
51 | /* Should all the messages be undeleted on startup */ | 42 | /* Should all the messages be undeleted on startup */ |
... | @@ -169,13 +160,6 @@ cb_bulletin_db (void *data, mu_config_value_t *val) | ... | @@ -169,13 +160,6 @@ cb_bulletin_db (void *data, mu_config_value_t *val) |
169 | } | 160 | } |
170 | #endif | 161 | #endif |
171 | 162 | ||
172 | struct pop3d_srv_config | ||
173 | { | ||
174 | struct mu_srv_config m_cfg; | ||
175 | enum tls_mode tls_mode; | ||
176 | }; | ||
177 | |||
178 | #ifdef WITH_TLS | ||
179 | static int | 163 | static int |
180 | cb_tls (void *data, mu_config_value_t *val) | 164 | cb_tls (void *data, mu_config_value_t *val) |
181 | { | 165 | { |
... | @@ -205,39 +189,14 @@ cb_tls (void *data, mu_config_value_t *val) | ... | @@ -205,39 +189,14 @@ cb_tls (void *data, mu_config_value_t *val) |
205 | return 0; | 189 | return 0; |
206 | } | 190 | } |
207 | 191 | ||
208 | static int | ||
209 | cb_tls_required (void *data, mu_config_value_t *val) | ||
210 | { | ||
211 | int bv; | ||
212 | |||
213 | if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) | ||
214 | return 1; | ||
215 | if (mu_str_to_c (val->v.string, mu_c_bool, &bv, NULL)) | ||
216 | mu_error (_("Not a boolean value")); | ||
217 | else if (bv) | ||
218 | { | ||
219 | tls_mode = tls_required; | ||
220 | mu_diag_output (MU_DIAG_WARNING, | ||
221 | "the \"tls-required\" statement is deprecated, " | ||
222 | "use \"tls required\" instead"); | ||
223 | } | ||
224 | else | ||
225 | mu_diag_output (MU_DIAG_WARNING, | ||
226 | "the \"tls-required\" statement is deprecated, " | ||
227 | "use \"tls\" instead"); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | #endif | ||
232 | |||
233 | static struct mu_cfg_param pop3d_srv_param[] = { | 192 | static struct mu_cfg_param pop3d_srv_param[] = { |
234 | #ifdef WITH_TLS | 193 | { "tls-mode", mu_cfg_callback, |
235 | { "tls", mu_cfg_callback, | ||
236 | NULL, mu_offsetof (struct pop3d_srv_config, tls_mode), cb_tls, | 194 | NULL, mu_offsetof (struct pop3d_srv_config, tls_mode), cb_tls, |
237 | N_("Kind of TLS encryption to use for this server"), | 195 | N_("Kind of TLS encryption to use for this server"), |
238 | /* TRANSLATORS: words to the right of : are keywords - do not translate */ | 196 | /* TRANSLATORS: words to the right of : are keywords - do not translate */ |
239 | N_("arg: false|true|ondemand|stls|requred|connection") }, | 197 | N_("arg: false|true|ondemand|stls|requred|connection") }, |
240 | #endif | 198 | { "tls", mu_cfg_section, |
199 | NULL, mu_offsetof (struct pop3d_srv_config, tls_conf) }, | ||
241 | { NULL } | 200 | { NULL } |
242 | }; | 201 | }; |
243 | 202 | ||
... | @@ -272,16 +231,8 @@ static struct mu_cfg_param pop3d_cfg_param[] = { | ... | @@ -272,16 +231,8 @@ static struct mu_cfg_param pop3d_cfg_param[] = { |
272 | " awrdir forbid files in world writable directories\n"), | 231 | " awrdir forbid files in world writable directories\n"), |
273 | N_("arg: list") }, | 232 | N_("arg: list") }, |
274 | 233 | ||
275 | #ifdef WITH_TLS | 234 | { "tls", mu_cfg_section, &global_tls_conf }, |
276 | { "tls", mu_cfg_callback, &tls_mode, 0, cb_tls, | 235 | |
277 | N_("Kind of TLS encryption to use"), | ||
278 | /* TRANSLATORS: words to the right of : are keywords - do not translate */ | ||
279 | N_("arg: false|true|ondemand|stls|requred|connection") }, | ||
280 | { "tls-required", mu_cfg_callback, &tls_mode, 0, cb_tls_required, | ||
281 | N_("Always require STLS before entering authentication phase.\n" | ||
282 | "Deprecated, use \"tls required\" instead."), | ||
283 | N_("arg: bool") }, | ||
284 | #endif | ||
285 | #ifdef ENABLE_LOGIN_DELAY | 236 | #ifdef ENABLE_LOGIN_DELAY |
286 | { "login-delay", mu_c_time, &login_delay, 0, NULL, | 237 | { "login-delay", mu_c_time, &login_delay, 0, NULL, |
287 | N_("Set the minimal allowed delay between two successive logins.") }, | 238 | N_("Set the minimal allowed delay between two successive logins.") }, |
... | @@ -355,7 +306,7 @@ pop3d_get_client_address (int fd, struct sockaddr_in *pcs) | ... | @@ -355,7 +306,7 @@ pop3d_get_client_address (int fd, struct sockaddr_in *pcs) |
355 | ofd -- output descriptor | 306 | ofd -- output descriptor |
356 | tls -- initiate encrypted connection */ | 307 | tls -- initiate encrypted connection */ |
357 | int | 308 | int |
358 | pop3d_mainloop (int ifd, int ofd, enum tls_mode tls) | 309 | pop3d_mainloop (int ifd, int ofd, struct pop3d_srv_config *cfg) |
359 | { | 310 | { |
360 | int status = OK; | 311 | int status = OK; |
361 | char buffer[512]; | 312 | char buffer[512]; |
... | @@ -365,24 +316,18 @@ pop3d_mainloop (int ifd, int ofd, enum tls_mode tls) | ... | @@ -365,24 +316,18 @@ pop3d_mainloop (int ifd, int ofd, enum tls_mode tls) |
365 | 316 | ||
366 | mu_set_signals (pop3d_child_signal, sigtab, MU_ARRAY_SIZE (sigtab)); | 317 | mu_set_signals (pop3d_child_signal, sigtab, MU_ARRAY_SIZE (sigtab)); |
367 | 318 | ||
368 | if (tls == tls_unspecified) | 319 | pop3d_setio (ifd, ofd, |
369 | tls = tls_available ? tls_ondemand : tls_no; | 320 | cfg->tls_mode == tls_connection ? &cfg->tls_conf : NULL); |
370 | else if (tls != tls_no && !tls_available) | ||
371 | { | ||
372 | mu_error (_("TLS is not configured, but requested in the " | ||
373 | "configuration")); | ||
374 | tls = tls_no; | ||
375 | } | ||
376 | |||
377 | pop3d_setio (ifd, ofd, tls == tls_connection); | ||
378 | 321 | ||
379 | if (tls == tls_required) | 322 | if (cfg->tls_mode == tls_required) |
380 | initial_state = INITIAL; | 323 | initial_state = INITIAL; |
381 | 324 | ||
382 | state = tls == tls_connection ? AUTHORIZATION : initial_state; | 325 | state = cfg->tls_mode == tls_connection ? AUTHORIZATION : initial_state; |
383 | 326 | ||
384 | pop3d_session_init (&session); | 327 | pop3d_session_init (&session); |
385 | session.tls = tls; | 328 | session.tls_mode = cfg->tls_mode; |
329 | session.tls_conf = &cfg->tls_conf; | ||
330 | |||
386 | /* FIXME: state should also be in the session? */ | 331 | /* FIXME: state should also be in the session? */ |
387 | 332 | ||
388 | /* Prepare the shared secret for APOP. */ | 333 | /* Prepare the shared secret for APOP. */ |
... | @@ -528,8 +473,7 @@ pop3d_connection (int fd, struct sockaddr *sa, int salen, | ... | @@ -528,8 +473,7 @@ pop3d_connection (int fd, struct sockaddr *sa, int salen, |
528 | else | 473 | else |
529 | rc = 1; | 474 | rc = 1; |
530 | 475 | ||
531 | pop3d_mainloop (fd, fd, | 476 | pop3d_mainloop (fd, fd, cfg); |
532 | cfg->tls_mode == tls_unspecified ? tls_mode : cfg->tls_mode); | ||
533 | 477 | ||
534 | if (rc == 0) | 478 | if (rc == 0) |
535 | clr_strerr_flt (); | 479 | clr_strerr_flt (); |
... | @@ -569,6 +513,7 @@ main (int argc, char **argv) | ... | @@ -569,6 +513,7 @@ main (int argc, char **argv) |
569 | mu_tcpwrapper_cfg_init (); | 513 | mu_tcpwrapper_cfg_init (); |
570 | manlock_cfg_init (); | 514 | manlock_cfg_init (); |
571 | mu_acl_cfg_init (); | 515 | mu_acl_cfg_init (); |
516 | mu_tls_cfg_init (); | ||
572 | 517 | ||
573 | mu_m_server_create (&server, program_version); | 518 | mu_m_server_create (&server, program_version); |
574 | mu_m_server_set_config_size (server, sizeof (struct pop3d_srv_config)); | 519 | mu_m_server_set_config_size (server, sizeof (struct pop3d_srv_config)); |
... | @@ -645,11 +590,7 @@ main (int argc, char **argv) | ... | @@ -645,11 +590,7 @@ main (int argc, char **argv) |
645 | umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */ | 590 | umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */ |
646 | 591 | ||
647 | /* Check TLS environment, i.e. cert and key files */ | 592 | /* Check TLS environment, i.e. cert and key files */ |
648 | #ifdef WITH_TLS | 593 | mu_m_server_set_preflight (server, stls_preflight); |
649 | tls_available = mu_check_tls_environment (); | ||
650 | if (tls_available) | ||
651 | enable_stls (); | ||
652 | #endif /* WITH_TLS */ | ||
653 | 594 | ||
654 | /* Actually run the daemon. */ | 595 | /* Actually run the daemon. */ |
655 | if (mu_m_server_mode (server) == MODE_DAEMON) | 596 | if (mu_m_server_mode (server) == MODE_DAEMON) |
... | @@ -661,9 +602,12 @@ main (int argc, char **argv) | ... | @@ -661,9 +602,12 @@ main (int argc, char **argv) |
661 | } | 602 | } |
662 | else | 603 | else |
663 | { | 604 | { |
605 | struct pop3d_srv_config cfg; | ||
606 | memset (&cfg, 0, sizeof cfg); | ||
607 | cfg.tls_mode = tls_no; | ||
664 | /* Make sure we are in the root directory. */ | 608 | /* Make sure we are in the root directory. */ |
665 | chdir ("/"); | 609 | chdir ("/"); |
666 | status = pop3d_mainloop (MU_STDIN_FD, MU_STDOUT_FD, tls_mode); | 610 | status = pop3d_mainloop (MU_STDIN_FD, MU_STDOUT_FD, &cfg); |
667 | } | 611 | } |
668 | 612 | ||
669 | if (status) | 613 | if (status) | ... | ... |
... | @@ -145,31 +145,32 @@ extern int expire_on_exit; | ... | @@ -145,31 +145,32 @@ extern int expire_on_exit; |
145 | #define UPDATE 2 | 145 | #define UPDATE 2 |
146 | #define ABORT 3 | 146 | #define ABORT 3 |
147 | 147 | ||
148 | #define OK 0 | 148 | enum pop3d_error { |
149 | #define ERR_WRONG_STATE 1 | 149 | OK = 0, |
150 | #define ERR_BAD_ARGS 2 | 150 | ERR_WRONG_STATE, |
151 | #define ERR_BAD_LOGIN 3 | 151 | ERR_BAD_ARGS, |
152 | #define ERR_NO_MESG 4 | 152 | ERR_BAD_LOGIN, |
153 | #define ERR_MESG_DELE 5 | 153 | ERR_NO_MESG, |
154 | #define ERR_NOT_IMPL 6 | 154 | ERR_MESG_DELE, |
155 | #define ERR_BAD_CMD 7 | 155 | ERR_NOT_IMPL, |
156 | #define ERR_MBOX_LOCK 8 | 156 | ERR_BAD_CMD, |
157 | #define ERR_TOO_LONG 9 | 157 | ERR_MBOX_LOCK, |
158 | #define ERR_NO_MEM 10 | 158 | ERR_TOO_LONG, |
159 | #define ERR_SIGNAL 11 | 159 | ERR_NO_MEM, |
160 | #define ERR_FILE 12 | 160 | ERR_SIGNAL, |
161 | #define ERR_NO_IFILE 13 | 161 | ERR_FILE, |
162 | #define ERR_NO_OFILE 14 | 162 | ERR_NO_IFILE, |
163 | #define ERR_IO 15 | 163 | ERR_NO_OFILE, |
164 | #define ERR_PROTO 16 | 164 | ERR_IO, |
165 | #define ERR_TIMEOUT 17 | 165 | ERR_PROTO, |
166 | #define ERR_UNKNOWN 18 | 166 | ERR_TIMEOUT, |
167 | #define ERR_MBOX_SYNC 19 | 167 | ERR_UNKNOWN, |
168 | #define ERR_TLS_ACTIVE 20 | 168 | ERR_MBOX_SYNC, |
169 | #define ERR_TLS_IO 21 | 169 | ERR_TLS_IO, |
170 | #define ERR_LOGIN_DELAY 22 | 170 | ERR_LOGIN_DELAY, |
171 | #define ERR_TERMINATE 23 | 171 | ERR_TERMINATE, |
172 | #define ERR_SYS_LOGIN 24 | 172 | ERR_SYS_LOGIN |
173 | }; | ||
173 | 174 | ||
174 | enum tls_mode | 175 | enum tls_mode |
175 | { | 176 | { |
... | @@ -200,7 +201,15 @@ struct pop3d_capa | ... | @@ -200,7 +201,15 @@ struct pop3d_capa |
200 | struct pop3d_session | 201 | struct pop3d_session |
201 | { | 202 | { |
202 | mu_list_t capa; | 203 | mu_list_t capa; |
203 | enum tls_mode tls; | 204 | enum tls_mode tls_mode; |
205 | struct mu_tls_config *tls_conf; | ||
206 | }; | ||
207 | |||
208 | struct pop3d_srv_config | ||
209 | { | ||
210 | struct mu_srv_config m_cfg; | ||
211 | enum tls_mode tls_mode; | ||
212 | struct mu_tls_config tls_conf; | ||
204 | }; | 213 | }; |
205 | 214 | ||
206 | void pop3d_session_init (struct pop3d_session *session); | 215 | void pop3d_session_init (struct pop3d_session *session); |
... | @@ -227,10 +236,7 @@ extern char *md5shared; | ... | @@ -227,10 +236,7 @@ extern char *md5shared; |
227 | extern size_t children; | 236 | extern size_t children; |
228 | extern struct daemon_param daemon_param; | 237 | extern struct daemon_param daemon_param; |
229 | extern int debug_mode; | 238 | extern int debug_mode; |
230 | #ifdef WITH_TLS | 239 | |
231 | extern int tls_available; | ||
232 | extern int tls_done; | ||
233 | #endif /* WITH_TLS */ | ||
234 | extern int undelete_on_startup; | 240 | extern int undelete_on_startup; |
235 | extern struct mu_auth_data *auth_data; | 241 | extern struct mu_auth_data *auth_data; |
236 | extern unsigned int idle_timeout; | 242 | extern unsigned int idle_timeout; |
... | @@ -242,6 +248,8 @@ extern int apop_database_safety; | ... | @@ -242,6 +248,8 @@ extern int apop_database_safety; |
242 | extern uid_t apop_database_owner; | 248 | extern uid_t apop_database_owner; |
243 | extern int apop_database_owner_set; | 249 | extern int apop_database_owner_set; |
244 | 250 | ||
251 | extern struct mu_tls_config global_tls_conf; | ||
252 | |||
245 | /* Safety checks for group-rw database files, such as stat and bulletin | 253 | /* Safety checks for group-rw database files, such as stat and bulletin |
246 | databases */ | 254 | databases */ |
247 | 255 | ||
... | @@ -282,13 +290,12 @@ extern void pop3d_parse_command (char *cmd, char **pcmd, char **parg); | ... | @@ -282,13 +290,12 @@ extern void pop3d_parse_command (char *cmd, char **pcmd, char **parg); |
282 | extern RETSIGTYPE pop3d_master_signal (int); | 290 | extern RETSIGTYPE pop3d_master_signal (int); |
283 | extern RETSIGTYPE pop3d_child_signal (int); | 291 | extern RETSIGTYPE pop3d_child_signal (int); |
284 | 292 | ||
285 | #ifdef WITH_TLS | ||
286 | extern int pop3d_stls (char *, struct pop3d_session *); | 293 | extern int pop3d_stls (char *, struct pop3d_session *); |
287 | extern void enable_stls (void); | 294 | int stls_preflight (mu_m_server_t msrv); |
288 | #endif /* WITH_TLS */ | 295 | |
289 | extern void pop3d_outf (const char *fmt, ...) MU_PRINTFLIKE(1,2); | 296 | extern void pop3d_outf (const char *fmt, ...) MU_PRINTFLIKE(1,2); |
290 | 297 | ||
291 | extern void pop3d_setio (int, int, int); | 298 | extern void pop3d_setio (int, int, struct mu_tls_config *); |
292 | extern char *pop3d_readline (char *, size_t); | 299 | extern char *pop3d_readline (char *, size_t); |
293 | extern void pop3d_flush_output (void); | 300 | extern void pop3d_flush_output (void); |
294 | 301 | ||
... | @@ -299,10 +306,7 @@ extern int pop3d_is_deleted (mu_attribute_t attr); | ... | @@ -299,10 +306,7 @@ extern int pop3d_is_deleted (mu_attribute_t attr); |
299 | extern void pop3d_unset_deleted (mu_attribute_t attr); | 306 | extern void pop3d_unset_deleted (mu_attribute_t attr); |
300 | void pop3d_undelete_all (void); | 307 | void pop3d_undelete_all (void); |
301 | 308 | ||
302 | #ifdef WITH_TLS | 309 | extern int pop3d_init_tls_server (struct mu_tls_config *tls_conf); |
303 | extern int pop3d_init_tls_server (void); | ||
304 | extern void pop3d_deinit_tls_server (void); | ||
305 | #endif /* WITH_TLS */ | ||
306 | 310 | ||
307 | extern void pop3d_mark_retr (mu_attribute_t attr); | 311 | extern void pop3d_mark_retr (mu_attribute_t attr); |
308 | extern int pop3d_is_retr (mu_attribute_t attr); | 312 | extern int pop3d_is_retr (mu_attribute_t attr); | ... | ... |
... | @@ -19,8 +19,6 @@ | ... | @@ -19,8 +19,6 @@ |
19 | 19 | ||
20 | /* STLS command -- TLS/SSL encryption */ | 20 | /* STLS command -- TLS/SSL encryption */ |
21 | 21 | ||
22 | #ifdef WITH_TLS | ||
23 | |||
24 | int | 22 | int |
25 | pop3d_stls (char *arg, struct pop3d_session *session) | 23 | pop3d_stls (char *arg, struct pop3d_session *session) |
26 | { | 24 | { |
... | @@ -30,7 +28,7 @@ pop3d_stls (char *arg, struct pop3d_session *session) | ... | @@ -30,7 +28,7 @@ pop3d_stls (char *arg, struct pop3d_session *session) |
30 | if (state != initial_state) | 28 | if (state != initial_state) |
31 | return ERR_WRONG_STATE; | 29 | return ERR_WRONG_STATE; |
32 | 30 | ||
33 | switch (session->tls) | 31 | switch (session->tls_mode) |
34 | { | 32 | { |
35 | case tls_ondemand: | 33 | case tls_ondemand: |
36 | case tls_required: | 34 | case tls_required: |
... | @@ -39,26 +37,20 @@ pop3d_stls (char *arg, struct pop3d_session *session) | ... | @@ -39,26 +37,20 @@ pop3d_stls (char *arg, struct pop3d_session *session) |
39 | return ERR_WRONG_STATE; | 37 | return ERR_WRONG_STATE; |
40 | } | 38 | } |
41 | 39 | ||
42 | if (tls_done) | ||
43 | return ERR_TLS_ACTIVE; | ||
44 | |||
45 | pop3d_outf ("+OK Begin TLS negotiation\n"); | 40 | pop3d_outf ("+OK Begin TLS negotiation\n"); |
46 | pop3d_flush_output (); | 41 | pop3d_flush_output (); |
47 | 42 | ||
48 | tls_done = pop3d_init_tls_server () == 0; | 43 | if (pop3d_init_tls_server (session->tls_conf)) |
49 | |||
50 | if (!tls_done) | ||
51 | { | 44 | { |
52 | mu_diag_output (MU_DIAG_ERROR, _("Session terminated")); | 45 | mu_diag_output (MU_DIAG_ERROR, _("Session terminated")); |
53 | state = ABORT; | 46 | state = ABORT; |
54 | return ERR_UNKNOWN; | 47 | return ERR_UNKNOWN; |
55 | } | 48 | } |
56 | 49 | ||
50 | session->tls_mode = tls_no; | ||
57 | state = AUTHORIZATION; /* Confirm we're in this state. Necessary for | 51 | state = AUTHORIZATION; /* Confirm we're in this state. Necessary for |
58 | "tls required" to work */ | 52 | "tls required" to work */ |
59 | 53 | ||
60 | return OK; | 54 | return OK; |
61 | } | 55 | } |
62 | 56 | ||
63 | #endif /* WITH_TLS */ | ||
64 | ... | ... |
-
Please register or sign in to post a comment