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 */
/* 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,10 +13,16 @@
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"
static FILE *ifile;
static FILE *ofile;
#ifdef WITH_TLS
static gnutls_session sfile;
#endif /* WITH_TLS */
static int add2set __P ((size_t **, int *, unsigned long));
static const char *sc2string __P ((int));
......@@ -36,7 +42,7 @@ util_getitem (char *s, const char *delim, char **save)
char *p;
if ((p = s) || (p = *save))
{
while (isspace ((unsigned)*p))
while (isspace ((unsigned) *p))
p++;
if (*p == '"')
{
......@@ -72,8 +78,7 @@ util_token (char *buf, size_t len, char **ptr)
if (**ptr == ' ' || **ptr == '.'
|| **ptr == '(' || **ptr == ')'
|| **ptr == '[' || **ptr == ']'
|| **ptr == '<' || **ptr == '>'
|| **ptr == '\r' || **ptr == '\n')
|| **ptr == '<' || **ptr == '>' || **ptr == '\r' || **ptr == '\n')
{
/* Advance. */
if (start == (*ptr))
......@@ -123,7 +128,8 @@ util_getfullpath (char *name, const char *delim)
char *p = util_tilde_expansion (name, delim);
if (*p != delim[0])
{
char *s = calloc (strlen (homedir) + strlen (delim) + strlen (p) + 1, 1);
char *s =
calloc (strlen (homedir) + strlen (delim) + strlen (p) + 1, 1);
sprintf (s, "%s%s%s", homedir, delim, p);
free (p);
p = s;
......@@ -134,7 +140,7 @@ util_getfullpath (char *name, const char *delim)
static int
comp_int (const void *a, const void *b)
{
return *(int*)a - *(int*)b;
return *(int *) a - *(int *) b;
}
/* Return in set an allocated array contain (n) numbers, for imap messsage set
......@@ -150,7 +156,7 @@ comp_int (const void *a, const void *b)
FIXME: The algo below is to relaxe, things like <,,,> or <:12> or <20:10>
will not generate an error. */
int
util_msgset (char *s, size_t **set, int *n, int isuid)
util_msgset (char *s, size_t ** set, int *n, int isuid)
{
unsigned long val = 0;
unsigned long low = 0;
......@@ -158,7 +164,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
int status = 0;
size_t max = 0;
size_t *tmp;
int i,j;
int i, j;
status = mailbox_messages_count (mbox, &max);
if (status != 0)
......@@ -178,8 +184,16 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
switch (*s)
{
/* isdigit */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
errno = 0;
val = strtoul (s, &s, 10);
......@@ -206,7 +220,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
low = val;
val = tmp;
}
for (;low && low <= val; low++)
for (; low && low <= val; low++)
{
status = add2set (set, n, low);
if (status != 0)
......@@ -284,7 +298,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
low = val;
val = tmp;
}
for (;low && low <= val; low++)
for (; low && low <= val; low++)
{
status = add2set (set, n, low);
if (status != 0)
......@@ -298,32 +312,49 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
/* Remove duplicates. tmp serves to avoid extra dereferences */
tmp = *set;
for (i = 0, j = 1; i < *n; i++)
if (tmp[j-1] != tmp[i])
if (tmp[j - 1] != tmp[i])
tmp[j++] = tmp[i];
*n = j;
return 0;
}
/* Use vfprintf for the dirty work. */
static int
util_send_lowlevel (char *buf)
{
int status;
if (buf)
{
#ifdef WITH_TLS
if (tls_done)
status = gnutls_record_send (sfile, buf, strlen (buf));
else
#endif /* WITH_TLS */
status = fprintf (ofile, buf);
}
return status;
}
int
util_send (const char *format, ...)
{
int status;
char *buf = NULL;
int status = 0;
va_list ap;
va_start (ap, format);
if (daemon_param.transcript)
{
char *buf;
va_start (ap, format);
vasprintf (&buf, format, ap);
if (buf)
{
if (daemon_param.transcript)
syslog (LOG_DEBUG, "sent: %s", buf);
status = util_send_lowlevel (buf);
free (buf);
}
}
status = vfprintf (ofile, format, ap);
va_end (ap);
return status;
}
......@@ -361,24 +392,26 @@ util_send_literal (const char *buffer)
int
util_out (int rc, const char *format, ...)
{
char *tempbuf = NULL;
char *buf = NULL;
int status;
int status = 0;
va_list ap;
asprintf (&buf, "* %s%s\r\n", sc2string (rc), format);
asprintf (&tempbuf, "* %s%s\r\n", sc2string (rc), format);
va_start (ap, format);
if (daemon_param.transcript)
{
char *buf1 = NULL;
vasprintf (&buf1, buf, ap);
if (buf1)
vasprintf (&buf, tempbuf, ap);
if (buf)
{
syslog (LOG_DEBUG, "sent: %s", buf1);
free (buf1);
}
if (daemon_param.transcript)
syslog (LOG_DEBUG, "sent: %s", buf);
status = util_send_lowlevel (buf);
free (buf);
}
status = vfprintf (ofile, buf, ap);
va_end (ap);
free (buf);
free (tempbuf);
return status;
}
......@@ -386,29 +419,29 @@ util_out (int rc, const char *format, ...)
int
util_finish (struct imap4d_command *command, int rc, const char *format, ...)
{
char *tempbuf = NULL;
char *buf = NULL;
int new_state;
int status;
int status = 0;
va_list ap;
asprintf (&buf, "%s %s%s %s\r\n", command->tag, sc2string (rc),
asprintf (&tempbuf, "%s %s%s %s\r\n", command->tag, sc2string (rc),
command->name, format);
va_start (ap, format);
if (daemon_param.transcript)
{
char *buf1 = NULL;
vasprintf (&buf1, buf, ap);
if (buf1)
vasprintf (&buf, tempbuf, ap);
if (buf)
{
syslog (LOG_DEBUG, "sent: %s", buf1);
free (buf1);
}
if (daemon_param.transcript)
syslog (LOG_DEBUG, "sent: %s", buf);
status = util_send_lowlevel (buf);
free (buf);
}
status = vfprintf (ofile, buf, ap);
va_end (ap);
free (buf);
free (tempbuf);
/* Reset the state. */
if (rc == RESP_OK)
new_state = command->success;
......@@ -419,6 +452,7 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
if (new_state != STATE_NONE)
state = new_state;
return status;
}
......@@ -429,7 +463,7 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
the number of octets, close brace ("}"), and CRLF.
*/
char *
imap4d_readline (FILE *fp)
imap4d_readline (void)
{
char buffer[512];
size_t len;
......@@ -444,9 +478,24 @@ imap4d_readline (FILE *fp)
do
{
alarm (daemon_param.timeout);
if (fgets (buffer, sizeof (buffer), fp) == NULL)
#ifdef WITH_TLS
if (tls_done)
{
len = gnutls_record_recv (sfile, buffer, sizeof (buffer) - 1);
if (len < 0)
{
syslog (LOG_INFO, _("TLS error on read: %s"),
gnutls_strerror (len));
imap4d_bye (ERR_TLS);
}
else
buffer[len] = 0;
}
else
#endif /* WITH_TLS */
if (fgets (buffer, sizeof (buffer), ifile) == NULL)
{
if (feof (fp))
if (feof (ifile))
syslog (LOG_INFO, _("unexpected eof on input"));
else if (errno)
syslog (LOG_INFO, _("error reading from input file: %m"));
......@@ -495,8 +544,9 @@ imap4d_readline (FILE *fp)
if (line[n] == '\n' && line[n - 1] == '}')
{
/* Search for the matching bracket. */
while (n && line[n] != '{') n--;
if (line [n] == '{')
while (n && line[n] != '{')
n--;
if (line[n] == '{')
{
char *sp = NULL;
/* Truncate where the literal number was. */
......@@ -517,13 +567,13 @@ imap4d_readline (FILE *fp)
}
char *
imap4d_readline_ex (FILE *fp)
imap4d_readline_ex (void)
{
int len;
char *s = imap4d_readline (fp);
char *s = imap4d_readline ();
if (s && (len = strlen (s)) > 0 && s[len-1] == '\n')
s[len-1] = 0;
if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n')
s[len - 1] = 0;
return s;
}
......@@ -540,7 +590,7 @@ util_do_command (char *prompt)
if (!tag)
{
nullcommand.name = "";
nullcommand.tag = (char *)"*";
nullcommand.tag = (char *) "*";
return util_finish (&nullcommand, RESP_BAD, "Null command");
}
else if (!cmd)
......@@ -577,7 +627,7 @@ util_upper (char *s)
if (!s)
return 0;
for (; *s; s++)
*s = toupper ((unsigned)*s);
*s = toupper ((unsigned) *s);
return 0;
}
......@@ -585,7 +635,7 @@ util_upper (char *s)
int
util_start (char *tag)
{
(void)tag;
(void) tag;
return 0;
}
......@@ -632,7 +682,7 @@ sc2string (int rc)
}
static int
add2set (size_t **set, int *n, unsigned long val)
add2set (size_t ** set, int *n, unsigned long val)
{
size_t *tmp;
tmp = realloc (*set, (*n + 1) * sizeof (**set));
......@@ -650,18 +700,18 @@ add2set (size_t **set, int *n, unsigned long val)
}
int
util_parse_internal_date0 (char *date, time_t *timep, char **endp)
util_parse_internal_date0 (char *date, time_t * timep, char **endp)
{
struct tm tm;
mu_timezone tz;
time_t time;
char **datep = &date;
if (mu_parse_imap_date_time((const char **)datep, &tm, &tz))
if (mu_parse_imap_date_time ((const char **) datep, &tm, &tz))
return 1;
time = mu_tm2time (&tm, &tz);
if (time == (time_t) -1)
if (time == (time_t) - 1)
return 2;
*timep = time;
......@@ -671,20 +721,20 @@ util_parse_internal_date0 (char *date, time_t *timep, char **endp)
}
int
util_parse_internal_date (char *date, time_t *timep)
util_parse_internal_date (char *date, time_t * timep)
{
return util_parse_internal_date0 (date, timep, NULL);
}
int
util_parse_822_date (char *date, time_t *timep)
util_parse_822_date (char *date, time_t * timep)
{
struct tm tm;
mu_timezone tz;
const char* p = date;
const char *p = date;
if (parse822_date_time(&p, date+strlen(date), &tm, &tz) == 0)
if (parse822_date_time (&p, date + strlen (date), &tm, &tz) == 0)
{
*timep = mu_tm2time (&tm, &tz);
return 0;
......@@ -693,12 +743,12 @@ util_parse_822_date (char *date, time_t *timep)
}
int
util_parse_ctime_date (const char *date, time_t *timep)
util_parse_ctime_date (const char *date, time_t * timep)
{
struct tm tm;
mu_timezone tz;
if (mu_parse_ctime_date_time(&date, &tm, &tz) == 0)
if (mu_parse_ctime_date_time (&date, &tm, &tz) == 0)
{
*timep = mu_tm2time (&tm, &tz);
return 0;
......@@ -711,8 +761,8 @@ util_parse_ctime_date (const char *date, time_t *timep)
char *
util_strcasestr (const char *haystack, const char *needle)
{
register char *needle_end = strchr(needle, '\0');
register char *haystack_end = strchr(haystack, '\0');
register char *needle_end = strchr (needle, '\0');
register char *haystack_end = strchr (haystack, '\0');
register size_t needle_len = needle_end - needle;
register size_t needle_last = needle_len - 1;
register const char *begin;
......@@ -729,7 +779,7 @@ util_strcasestr (const char *haystack, const char *needle)
register const char *h = begin;
do
if (tolower(*h) != tolower(*n))
if (tolower (*h) != tolower (*n))
goto loop; /* continue for loop */
while (--n >= needle && --h >= haystack);
......@@ -746,14 +796,27 @@ struct
{
char *name;
int flag;
} _imap4d_attrlist[] = {
{ "\\Answered", MU_ATTRIBUTE_ANSWERED },
{ "\\Flagged", MU_ATTRIBUTE_FLAGGED },
{ "\\Deleted", MU_ATTRIBUTE_DELETED },
{ "\\Draft", MU_ATTRIBUTE_DRAFT },
{ "\\Seen", MU_ATTRIBUTE_READ },
{ "\\Recent", MU_ATTRIBUTE_RECENT },
};
}
_imap4d_attrlist[] =
{
{
"\\Answered", MU_ATTRIBUTE_ANSWERED}
,
{
"\\Flagged", MU_ATTRIBUTE_FLAGGED}
,
{
"\\Deleted", MU_ATTRIBUTE_DELETED}
,
{
"\\Draft", MU_ATTRIBUTE_DRAFT}
,
{
"\\Seen", MU_ATTRIBUTE_READ}
,
{
"\\Recent", MU_ATTRIBUTE_RECENT}
,};
#define NATTR sizeof(_imap4d_attrlist)/sizeof(_imap4d_attrlist[0])
......@@ -781,8 +844,8 @@ util_type_to_attribute (int type, char **attr_str)
int i;
size_t len = 0;
if (MU_ATTRIBUTE_IS_UNSEEN(type))
*attr_str = strdup("\\Recent");
if (MU_ATTRIBUTE_IS_UNSEEN (type))
*attr_str = strdup ("\\Recent");
else
*attr_str = NULL;
......@@ -790,18 +853,18 @@ util_type_to_attribute (int type, char **attr_str)
if (type & _imap4d_attrlist[i].flag)
{
attr_list[nattr++] = _imap4d_attrlist[i].name;
len += 1 + strlen(_imap4d_attrlist[i].name);
len += 1 + strlen (_imap4d_attrlist[i].name);
}
*attr_str = malloc(len+1);
*attr_str = malloc (len + 1);
(*attr_str)[0] = 0;
if (*attr_str)
{
for (i = 0; i < nattr; i++)
{
strcat(*attr_str, attr_list[i]);
if (i != nattr-1)
strcat(*attr_str, " ");
strcat (*attr_str, attr_list[i]);
if (i != nattr - 1)
strcat (*attr_str, " ");
}
}
......@@ -811,7 +874,7 @@ util_type_to_attribute (int type, char **attr_str)
}
void
util_print_flags(attribute_t attr)
util_print_flags (attribute_t attr)
{
int i;
int flags = 0;
......@@ -828,7 +891,7 @@ util_print_flags(attribute_t attr)
util_send (_imap4d_attrlist[i].name);
}
if (MU_ATTRIBUTE_IS_UNSEEN(flags))
if (MU_ATTRIBUTE_IS_UNSEEN (flags))
{
if (space)
util_send (" ");
......@@ -851,7 +914,7 @@ util_attribute_matches_flag (attribute_t attr, const char *item)
int
util_parse_attributes(char *items, char **save, int *flags)
util_parse_attributes (char *items, char **save, int *flags)
{
int rc = 0;
......@@ -880,7 +943,7 @@ util_parse_attributes(char *items, char **save, int *flags)
int
util_base64_encode (const unsigned char *input, size_t input_len,
unsigned char **output, size_t *output_len)
unsigned char **output, size_t * output_len)
{
static char b64tab[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
......@@ -917,7 +980,7 @@ util_base64_encode (const unsigned char *input, size_t input_len,
int
util_base64_decode (const unsigned char *input, size_t input_len,
unsigned char **output, size_t *output_len)
unsigned char **output, size_t * output_len)
{
static int b64val[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
......@@ -940,7 +1003,8 @@ util_base64_decode (const unsigned char *input, size_t input_len,
if (input[0] > 127 || b64val[input[0]] == -1
|| input[1] > 127 || b64val[input[1]] == -1
|| input[2] > 127 || ((input[2] != '=') && (b64val[input[2]] == -1))
|| input[3] > 127 || ((input[3] != '=') && (b64val[input[3]] == -1)))
|| input[3] > 127 || ((input[3] != '=')
&& (b64val[input[3]] == -1)))
return -1;
*out++ = (b64val[input[0]] << 2) | (b64val[input[1]] >> 4);
if (input[2] != '=')
......@@ -987,13 +1051,13 @@ util_localname ()
if (hp)
{
struct in_addr inaddr;
inaddr.s_addr = *(unsigned int*)hp->h_addr;
hp = gethostbyaddr ((const char *)&inaddr,
inaddr.s_addr = *(unsigned int *) hp->h_addr;
hp = gethostbyaddr ((const char *) &inaddr,
sizeof (struct in_addr), AF_INET);
if (hp)
{
free (name);
name = strdup ((char *)hp->h_name);
name = strdup ((char *) hp->h_name);
}
}
localname = name;
......@@ -1009,7 +1073,7 @@ util_wcard_match (const char *string, const char *pattern, const char *delim)
const char *p = pattern, *n = string;
char c;
for (;(c = *p++) != '\0' && *n; n++)
for (; (c = *p++) != '\0' && *n; n++)
{
switch (c)
{
......@@ -1071,3 +1135,48 @@ util_uidvalidity (mailbox_t smbox, unsigned long *uidvp)
smbox = mbox;
return mailbox_uidvalidity (smbox, uidvp);
}
void
util_setio (int infile, int outfile)
{
ifile = fdopen (infile, "r");
ofile = fdopen (outfile, "w");
if (!ofile || !ifile)
imap4d_bye (ERR_NO_OFILE);
setvbuf (ofile, NULL, _IOLBF, 0);
}
void
util_flush_output ()
{
if (!tls_done)
fflush (ofile);
}
FILE *
util_is_ofile ()
{
return ofile;
}
#ifdef WITH_TLS
int
imap4d_init_tls_server ()
{
sfile =
(gnutls_session) mu_init_tls_server (fileno (ifile), fileno (ofile));
if (!sfile)
return 0;
return 1;
}
void
imap4d_deinit_tls_server ()
{
mu_deinit_tls_server (sfile);
}
#endif /* WITH_TLS */
......