Commit 6b97e35b 6b97e35bebf12ea2a4e2d47a2c056ef53e46bd3d by Wojciech Polak

Added TLS/SSL support (via GnuTLS)

1 parent 3311ee56
## Process this file with GNU Automake to create Makefile.in
## Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
## Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
##
## GNU Mailtuils is free software; you can redistribute it and/or
## GNU Mailutils is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2, or (at
## your option) any later version.
##
## This program is distributed in the hope that it will be useful, but
## GNU Mailutils is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## along with GNU Mailutils; if not, write to the Free Software
## Foundation, Inc.
## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
......@@ -26,8 +26,8 @@ imap4d_LDADD = @AUTHOBJS@ ../mailbox/libmailbox.la @AUTHLIBS@ ../lib/libmailuti
imap4d_SOURCES = append.c authenticate.c bye.c capability.c check.c close.c \
commands.c copy.c create.c delete.c examine.c expunge.c fetch.c imap4d.c \
imap4d.h list.c logout.c login.c lsub.c namespace.c noop.c rename.c search.c \
select.c signal.c status.c store.c subscribe.c sync.c uid.c unsubscribe.c \
util.c version.c
select.c signal.c starttls.c status.c store.c subscribe.c sync.c uid.c \
unsubscribe.c util.c version.c
## This kludge is necessary to correctly establish imap4d -> AUTHOBJS
## dependency. Think about better approach --gray
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -13,9 +13,10 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* GSSAPI authentication for imap (rfc 1731).
/*
GSSAPI authentication for imap (rfc 1731).
*/
#include "imap4d.h"
......@@ -46,11 +47,8 @@ display_status_1 (char *m, OM_uint32 code, int type)
do
{
maj_stat = gss_display_status (&min_stat, code,
type, GSS_C_NULL_OID,
&msg_ctx, &msg);
syslog (LOG_ERR,
_("GSS-API error %s: %s\n"), m,
(char *)msg.value);
type, GSS_C_NULL_OID, &msg_ctx, &msg);
syslog (LOG_ERR, _("GSS-API error %s: %s\n"), m, (char *) msg.value);
gss_release_buffer (&min_stat, &msg);
}
while (msg_ctx);
......@@ -64,7 +62,7 @@ display_status (char *msg, OM_uint32 maj_stat, OM_uint32 min_stat)
}
static int
imap4d_gss_userok(gss_buffer_t client_name, char *name)
imap4d_gss_userok (gss_buffer_t client_name, char *name)
{
int rc = -1;
krb5_principal p;
......@@ -109,30 +107,27 @@ auth_gssapi (struct imap4d_command *command, char **username)
work (possibly due to a bug in krb5_gss_accept_sec_context()), so
we acquire server credentials explicitly. */
asprintf ((char**)&tmp, "imap@%s", util_localname ());
asprintf ((char **) &tmp, "imap@%s", util_localname ());
tokbuf.value = tmp;
tokbuf.length = strlen (tokbuf.value) + 1;
maj_stat = gss_import_name (&min_stat, &tokbuf,
gss_nt_service_name,
&server_name);
gss_nt_service_name, &server_name);
if (maj_stat != GSS_S_COMPLETE)
{
display_status ("import name", maj_stat, min_stat);
util_finish (command, RESP_NO,
"GSSAPI authentication not available");
util_finish (command, RESP_NO, "GSSAPI authentication not available");
return 1;
}
maj_stat = gss_acquire_cred (&min_stat, server_name, 0,
GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
&server_creds, NULL, NULL);
gss_release_name(&min_stat2, &server_name);
gss_release_name (&min_stat2, &server_name);
if (maj_stat != GSS_S_COMPLETE)
{
display_status ("acquire credentials", maj_stat, min_stat);
util_finish (command, RESP_NO,
"GSSAPI authentication not available");
util_finish (command, RESP_NO, "GSSAPI authentication not available");
return 1;
}
......@@ -144,7 +139,7 @@ auth_gssapi (struct imap4d_command *command, char **username)
for (;;)
{
token_str = imap4d_readline_ex (ifile);
token_str = imap4d_readline_ex ();
util_base64_decode (token_str, strlen (token_str), &tmp, &size);
tokbuf.value = tmp;
tokbuf.length = size;
......@@ -158,9 +153,7 @@ auth_gssapi (struct imap4d_command *command, char **username)
&client,
&mech_type,
&outbuf,
&cflags,
NULL,
&cred_handle);
&cflags, NULL, &cred_handle);
free (tmp);
if (maj_stat == GSS_S_CONTINUE_NEEDED)
{
......@@ -180,8 +173,7 @@ auth_gssapi (struct imap4d_command *command, char **username)
display_status ("accept context", maj_stat, min_stat);
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
util_finish (command, RESP_NO,
"GSSAPI authentication failed");
util_finish (command, RESP_NO, "GSSAPI authentication failed");
return 1;
}
......@@ -191,7 +183,7 @@ auth_gssapi (struct imap4d_command *command, char **username)
util_send ("+ %*.*s\r\n", size, size, tmp);
free (tmp);
gss_release_buffer (&min_stat, &outbuf);
token_str = imap4d_readline_ex (ifile);
token_str = imap4d_readline_ex ();
free (token_str);
}
......@@ -205,15 +197,15 @@ auth_gssapi (struct imap4d_command *command, char **username)
util_send ("+ %*.*s\r\n", size, size, tmp);
free (tmp);
token_str = imap4d_readline_ex (ifile);
token_str = imap4d_readline_ex ();
util_base64_decode (token_str, strlen (token_str),
(unsigned char **)&tokbuf.value, &tokbuf.length);
(unsigned char **) &tokbuf.value, &tokbuf.length);
free (token_str);
gss_unwrap (&min_stat, context, &tokbuf, &outbuf, &cflags, &quality);
free (tokbuf.value);
sec_level = ntohl (*(OM_uint32*)outbuf.value);
sec_level = ntohl (*(OM_uint32 *) outbuf.value);
/* FIXME: parse sec_level and act accordingly to its settings */
mech = sec_level >> 24;
......@@ -232,19 +224,17 @@ auth_gssapi (struct imap4d_command *command, char **username)
protection_mech = mech;
client_buffer_size = sec_level & 0x00ffffffff;
*username = strdup ((char*)outbuf.value + 4);
*username = strdup ((char *) outbuf.value + 4);
gss_release_buffer (&min_stat, &outbuf);
maj_stat = gss_display_name(&min_stat, client,
&client_name, &mech_type);
maj_stat = gss_display_name (&min_stat, client, &client_name, &mech_type);
if (maj_stat != GSS_S_COMPLETE)
{
display_status ("get client name", maj_stat, min_stat);
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
free (*username);
util_finish (command, RESP_NO,
"GSSAPI authentication failed");
util_finish (command, RESP_NO, "GSSAPI authentication failed");
return 1;
}
......@@ -270,8 +260,6 @@ auth_gssapi (struct imap4d_command *command, char **username)
gss_release_buffer (&min_stat, &client_name);
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
util_finish (command, RESP_OK,
"GSSAPI authentication successful");
util_finish (command, RESP_OK, "GSSAPI authentication successful");
return 0;
}
......
......@@ -44,7 +44,7 @@ imap4d_bye0 (int reason, struct imap4d_command *command)
break;
case ERR_SIGNAL:
if (ofile)
if (util_is_ofile())
util_out (RESP_BYE, "Quitting on signal");
syslog (LOG_ERR, _("Quitting on signal"));
break;
......@@ -78,6 +78,14 @@ imap4d_bye0 (int reason, struct imap4d_command *command)
if (status == EXIT_SUCCESS && command)
util_finish (command, RESP_OK, "Completed");
#ifdef WITH_TLS
if (tls_done)
imap4d_deinit_tls_server ();
if (tls_available)
mu_deinit_tls_libs ();
#endif /* WITH_TLS */
closelog ();
exit (status);
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001 Free Software Foundation, Inc.
Copyright (C) 1999, 2001, 2003 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "imap4d.h"
......@@ -29,12 +29,19 @@ imap4d_capability (struct imap4d_command *command, char *arg)
{
int i;
(void)arg;
(void) arg;
util_send ("* CAPABILITY");
for (i = 0; capa[i]; i++)
util_send(" %s", capa[i]);
util_send (" %s", capa[i]);
#ifdef WITH_TLS
if (tls_available)
util_send (" STARTTLS");
#endif /* WITH_TLS */
imap4d_auth_capability ();
util_send("\r\n");
util_send ("\r\n");
return util_finish (command, RESP_OK, "Completed");
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001 Free Software Foundation, Inc.
Copyright (C) 1999, 2001, 2003 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "imap4d.h"
......@@ -45,5 +45,8 @@ struct imap4d_command imap4d_command_table [] =
{ "UID", imap4d_uid, STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "NAMESPACE", imap4d_namespace, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "X-VERSION", imap4d_version, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
#ifdef WITH_TLS
{ "STARTTLS", imap4d_starttls, STATE_NONAUTH, STATE_NONE, STATE_NONE, NULL },
#endif /* WITH_TLS */
{ NULL, 0, 0, 0, 0, NULL }
};
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -13,12 +13,10 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "imap4d.h"
FILE *ifile;
FILE *ofile;
mailbox_t mbox;
char *homedir;
int state = STATE_NONAUTH;
......@@ -33,22 +31,27 @@ struct daemon_param daemon_param = {
0 /* No transcript by default */
};
#ifdef WITH_TLS
int tls_available;
int tls_done;
#endif /* WITH_TLS */
/* Number of child processes. */
volatile size_t children;
const char *argp_program_version = "imap4d (" PACKAGE_STRING ")";
static char doc[] = N_("GNU imap4d -- the IMAP4D daemon");
static struct argp_option options[] =
{
static struct argp_option options[] = {
{"other-namespace", 'O', N_("PATHLIST"), 0,
N_("set the `other' namespace"), 0},
{"shared-namespace", 'S', N_("PATHLIST"), 0,
N_("set the `shared' namespace"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
{NULL, 0, NULL, 0, NULL, 0}
};
static error_t imap4d_parse_opt (int key, char *arg, struct argp_state *state);
static error_t imap4d_parse_opt (int key, char *arg,
struct argp_state *state);
static struct argp argp = {
options,
......@@ -62,6 +65,9 @@ static struct argp argp = {
static const char *imap4d_capa[] = {
"daemon",
"auth",
#ifdef WITH_TLS
"tls",
#endif /* WITH_TLS */
"common",
"mailbox",
"logging",
......@@ -108,7 +114,10 @@ main (int argc, char **argv)
state = STATE_NONAUTH; /* Starting state in non-auth. */
MU_AUTH_REGISTER_ALL_MODULES();
MU_AUTH_REGISTER_ALL_MODULES ();
#ifdef WITH_TLS
mu_tls_init_argp ();
#endif /* WITH_TLS */
mu_argp_parse (&argp, &argc, &argv, 0, imap4d_capa, NULL, &daemon_param);
#ifdef USE_LIBPAM
......@@ -177,6 +186,13 @@ main (int argc, char **argv)
umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */
/* Check TLS environment, i.e. cert and key files */
#ifdef WITH_TLS
tls_available = mu_check_tls_environment ();
if (tls_available)
tls_available = mu_init_tls_libs ();
#endif /* WITH_TLS */
/* Actually run the daemon. */
if (daemon_param.mode == MODE_DAEMON)
imap4d_daemon (daemon_param.maxchildren, daemon_param.port);
......@@ -200,12 +216,7 @@ imap4d_mainloop (int infile, int outfile)
/* Timeout alarm. */
signal (SIGALRM, imap4d_signal);
ifile = fdopen (infile, "r");
ofile = fdopen (outfile, "w");
if (!ofile || !ifile)
imap4d_bye (ERR_NO_OFILE);
setvbuf(ofile, NULL, _IOLBF, 0);
util_setio (infile, outfile);
/* log information on the connecting client */
if (!debug_mode)
......@@ -214,11 +225,11 @@ imap4d_mainloop (int infile, int outfile)
int len = sizeof cs;
syslog (LOG_INFO, _("Incoming connection opened"));
if (getpeername (infile, (struct sockaddr*)&cs, &len) < 0)
if (getpeername (infile, (struct sockaddr *) &cs, &len) < 0)
syslog (LOG_ERR, _("can't obtain IP address of client: %s"),
strerror (errno));
else
syslog (LOG_INFO, _("connect from %s"), inet_ntoa(cs.sin_addr));
syslog (LOG_INFO, _("connect from %s"), inet_ntoa (cs.sin_addr));
text = "IMAP4rev1";
}
else
......@@ -229,20 +240,19 @@ imap4d_mainloop (int infile, int outfile)
/* Greetings. */
util_out (RESP_OK, text);
fflush (ofile);
util_flush_output ();
while (1)
{
char *cmd = imap4d_readline (ifile);
char *cmd = imap4d_readline ();
/* check for updates */
imap4d_sync ();
util_do_command (cmd);
imap4d_sync ();
free (cmd);
fflush (ofile);
util_flush_output ();
}
closelog ();
return EXIT_SUCCESS;
}
......@@ -256,7 +266,7 @@ imap4d_daemon_init (void)
first three one, in, out, err */
if (daemon (0, 0) < 0)
{
perror(_("fork failed:"));
perror (_("fork failed:"));
exit (1);
}
......@@ -289,18 +299,18 @@ imap4d_daemon (unsigned int maxchildren, unsigned int port)
listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
syslog (LOG_ERR, "socket: %s", strerror(errno));
syslog (LOG_ERR, "socket: %s", strerror (errno));
exit (1);
}
size = 1; /* Use size here to avoid making a new variable. */
setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &size, sizeof(size));
setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &size, sizeof (size));
size = sizeof (server);
memset (&server, 0, size);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (port);
if (bind (listenfd, (struct sockaddr *)&server, size) == -1)
if (bind (listenfd, (struct sockaddr *) &server, size) == -1)
{
syslog (LOG_ERR, "bind: %s", strerror (errno));
exit (1);
......@@ -321,8 +331,8 @@ imap4d_daemon (unsigned int maxchildren, unsigned int port)
pause ();
continue;
}
connfd = accept (listenfd, (struct sockaddr *)&client,
(socklen_t*) &size);
connfd = accept (listenfd, (struct sockaddr *) &client,
(socklen_t *) & size);
if (connfd == -1)
{
if (errno == EINTR)
......@@ -333,7 +343,7 @@ imap4d_daemon (unsigned int maxchildren, unsigned int port)
pid = fork ();
if (pid == -1)
syslog(LOG_ERR, "fork: %s", strerror (errno));
syslog (LOG_ERR, "fork: %s", strerror (errno));
else if (pid == 0) /* Child. */
{
int status;
......@@ -349,4 +359,3 @@ imap4d_daemon (unsigned int maxchildren, unsigned int port)
close (connfd);
}
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _IMAP4D_H
#define _IMAP4D_H 1
......@@ -87,6 +87,7 @@
#include <mailutils/stream.h>
#include <mailutils/mu_auth.h>
#include <mailutils/url.h>
#include <mailutils/tls.h>
#include <mailutils/nls.h>
#ifdef __cplusplus
......@@ -126,6 +127,7 @@ struct imap4d_command
#define ERR_NO_OFILE 2
#define ERR_TIMEOUT 3
#define ERR_SIGNAL 4
#define ERR_TLS 5
/* Namespace numbers */
#define NS_PRIVATE 0
......@@ -139,8 +141,6 @@ struct imap4d_command
#define WCARD_RECURSE_MATCH 2
extern struct imap4d_command imap4d_command_table[];
extern FILE *ifile;
extern FILE *ofile;
extern mailbox_t mbox;
extern char *homedir;
extern char *rootdir;
......@@ -150,6 +150,11 @@ extern int is_virtual;
extern struct daemon_param daemon_param;
extern struct mu_auth_data *auth_data;
#ifdef WITH_TLS
extern int tls_available;
extern int tls_done;
#endif /* WITH_TLS */
#ifndef HAVE_STRTOK_R
extern char *strtok_r __P((char *s, const char *delim, char **save_ptr));
#endif
......@@ -181,6 +186,9 @@ extern int imap4d_search0 __P((char *arg, int isuid, char *replybuf, size_t rep
extern int imap4d_select __P ((struct imap4d_command *, char *));
extern int imap4d_select0 __P ((struct imap4d_command *, char *, int));
extern int imap4d_select_status __P((void));
#ifdef WITH_TLS
extern int imap4d_starttls __P ((struct imap4d_command *, char *));
#endif /* WITH_TLS */
extern int imap4d_status __P ((struct imap4d_command *, char *));
extern int imap4d_store __P ((struct imap4d_command *, char *));
extern int imap4d_store0 __P ((char *, int, char *, size_t));
......@@ -220,8 +228,8 @@ extern int util_start __P ((char *));
extern int util_finish __P ((struct imap4d_command *, int, const char *, ...));
extern int util_getstate __P ((void));
extern int util_do_command __P ((char *));
extern char *imap4d_readline __P ((FILE*));
extern char *imap4d_readline_ex __P ((FILE*));
extern char *imap4d_readline __P ((void));
extern char *imap4d_readline_ex __P ((void));
extern char *util_getword __P ((char *, char **));
extern char *util_getitem __P ((char *, const char *, char **));
extern int util_token __P ((char *, size_t, char **));
......@@ -257,6 +265,14 @@ int util_type_to_attribute __P((int type, char **attr_str));
int util_attribute_matches_flag __P((attribute_t attr, const char *item));
int util_uidvalidity __P((mailbox_t smbox, unsigned long *uidvp));
void util_setio __P((int, int));
void util_flush_output __P((void));
FILE *util_is_ofile __P((void));
#ifdef WITH_TLS
int imap4d_init_tls_server __P((void));
void imap4d_deinit_tls_server __P((void));
#endif /* WITH_TLS */
#ifdef __cplusplus
}
#endif
......
......@@ -41,7 +41,7 @@ imap4d_signal (int signo)
{
syslog (LOG_CRIT, _("got signal %s"), strsignal (signo));
/* Master process. */
if (!ofile)
if (!(util_is_ofile()))
{
syslog (LOG_CRIT, _("MASTER: exiting on signal"));
exit (1); /* abort(); */
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "imap4d.h"
#ifdef WITH_TLS
int
imap4d_starttls (struct imap4d_command *command, char *arg)
{
int status;
char *sp = NULL;
if (!tls_available || tls_done)
return util_finish (command, RESP_BAD, "Invalid command");
if (util_getword (arg, &sp))
return util_finish (command, RESP_BAD, "Too many args");
status = util_finish (command, RESP_OK, "Begin TLS negotiation");
tls_done = imap4d_init_tls_server ();
return status;
}
#endif /* WITH_TLS */
/* EOF */