commit b6089a2dcb082acd71e0cfd4c9d75b96db2e0b83
parent 813618f041d818986ec9a3d1ee0e6ca801b3087b
Author: Michael Elkins <me@mutt.org>
Date: Thu, 21 Dec 2000 06:27:05 +0000
added OpenSSL support
Diffstat:
M | configure.in | | | 2 | ++ |
M | imap.c | | | 118 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | isync.1 | | | 32 | +++++++++++++++++++++++++------- |
M | isync.h | | | 23 | ++++++++++++++++++++++- |
M | main.c | | | 75 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
5 files changed, 214 insertions(+), 36 deletions(-)
diff --git a/configure.in b/configure.in
@@ -5,5 +5,7 @@ if test $CC = gcc; then
CFLAGS="$CFLAGS -pipe"
fi
AC_CHECK_FUNCS(getopt_long)
+AC_CHECK_LIB(crypto,ERR_error_string)
+AC_CHECK_LIB(ssl,SSL_library_init)
CFLAGS="$CFLAGS -W -Wall -pedantic -Wmissing-prototypes -Wmissing-declarations"
AC_OUTPUT(Makefile)
diff --git a/imap.c b/imap.c
@@ -29,6 +29,9 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
+#if HAVE_LIBSSL
+#include <openssl/err.h>
+#endif
#include "isync.h"
const char *Flags[] = {
@@ -40,6 +43,56 @@ const char *Flags[] = {
"\\Draft"
};
+#if HAVE_LIBSSL
+SSL_CTX *SSLContext = 0;
+
+static int
+init_ssl (config_t * conf)
+{
+ if (!conf->cert_file)
+ {
+ puts ("Error, CertificateFile not defined");
+ return -1;
+ }
+ SSL_library_init ();
+ SSL_load_error_strings ();
+ SSLContext = SSL_CTX_new (SSLv23_client_method ());
+ if (!SSL_CTX_load_verify_locations (SSLContext, conf->cert_file, NULL))
+ {
+ printf ("Error, SSL_CTX_load_verify_locations: %s\n",
+ ERR_error_string (ERR_get_error (), 0));
+ return -1;
+ }
+ SSL_CTX_set_verify (SSLContext,
+ SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
+ SSL_VERIFY_CLIENT_ONCE, NULL);
+ SSL_CTX_set_verify_depth (SSLContext, 1);
+ return 0;
+}
+
+#endif
+
+static int
+socket_read (Socket_t * sock, char *buf, size_t len)
+{
+#if HAVE_LIBSSL
+ if (sock->use_ssl)
+ return SSL_read (sock->ssl, buf, len);
+#endif
+ return read (sock->fd, buf, len);
+}
+
+static int
+socket_write (Socket_t * sock, char *buf, size_t len)
+{
+#if HAVE_LIBSSL
+ if (sock->use_ssl)
+ return SSL_write (sock->ssl, buf, len);
+#endif
+ return write (sock->fd, buf, len);
+}
+
/* simple line buffering */
static int
buffer_gets (buffer_t * b, char **s)
@@ -64,7 +117,10 @@ buffer_gets (buffer_t * b, char **s)
b->offset = n;
start = 0;
- n = read (b->fd, b->buf + b->offset, sizeof (b->buf) - b->offset);
+ n =
+ socket_read (b->sock, b->buf + b->offset,
+ sizeof (b->buf) - b->offset);
+
if (n <= 0)
{
if (n == -1)
@@ -112,7 +168,7 @@ imap_exec (imap_t * imap, const char *fmt, ...)
snprintf (buf, sizeof (buf), "%d %s\r\n", ++Tag, tmp);
if (Verbose)
fputs (buf, stdout);
- write (imap->fd, buf, strlen (buf));
+ socket_write (imap->sock, buf, strlen (buf));
for (;;)
{
@@ -223,7 +279,6 @@ imap_exec (imap_t * imap, const char *fmt, ...)
arg = next_arg (&cmd);
if (!strcmp ("OK", arg))
return 0;
- puts ("IMAP command failed");
return -1;
}
}
@@ -289,6 +344,15 @@ imap_open (config_t * box, int fast)
int s;
struct sockaddr_in sin;
struct hostent *he;
+#if HAVE_LIBSSL
+ int use_ssl = 0;
+#endif
+
+#if HAVE_LIBSSL
+ /* initialize SSL */
+ if (init_ssl (box))
+ return 0;
+#endif
/* open connection to IMAP server */
@@ -321,12 +385,46 @@ imap_open (config_t * box, int fast)
puts ("ok");
imap = calloc (1, sizeof (imap_t));
- imap->fd = s;
- //imap->state = imap_state_init;
+ imap->sock = calloc (1, sizeof (Socket_t));
+ imap->sock->fd = s;
imap->buf = calloc (1, sizeof (buffer_t));
- imap->buf->fd = s;
+ imap->buf->sock = imap->sock;
imap->box = box;
+#if HAVE_LIBSSL
+ if (!box->use_imaps)
+ {
+ /* always try to select SSL support if available */
+ ret = imap_exec (imap, "STARTTLS");
+ if (!ret)
+ use_ssl = 1;
+ else if (box->require_ssl)
+ {
+ puts ("Error, SSL support not available");
+ return 0;
+ }
+ else
+ puts ("Warning, SSL support not available");
+ }
+ else
+ use_ssl = 1;
+
+ if (use_ssl)
+ {
+ imap->sock->ssl = SSL_new (SSLContext);
+ SSL_set_fd (imap->sock->ssl, imap->sock->fd);
+ ret = SSL_connect (imap->sock->ssl);
+ if (ret <= 0)
+ {
+ ret = SSL_get_error (imap->sock->ssl, ret);
+ printf ("Error, SSL_connect: %s\n", ERR_error_string (ret, 0));
+ return 0;
+ }
+ imap->sock->use_ssl = 1;
+ puts ("SSL support enabled");
+ }
+#endif
+
puts ("Logging in...");
ret = imap_exec (imap, "LOGIN %s %s", box->user, box->pass);
if (!ret)
@@ -395,7 +493,7 @@ write_strip (int fd, char *buf, size_t len)
}
static void
-send_server (int fd, const char *fmt, ...)
+send_server (Socket_t * sock, const char *fmt, ...)
{
char buf[128];
char cmd[128];
@@ -406,7 +504,7 @@ send_server (int fd, const char *fmt, ...)
va_end (ap);
snprintf (cmd, sizeof (cmd), "%d %s\r\n", ++Tag, buf);
- write (fd, cmd, strlen (cmd));
+ socket_write (sock, cmd, strlen (cmd));
if (Verbose)
fputs (cmd, stdout);
@@ -421,7 +519,7 @@ imap_fetch_message (imap_t * imap, unsigned int uid, int fd)
size_t n;
char buf[1024];
- send_server (imap->fd, "UID FETCH %d RFC822.PEEK", uid);
+ send_server (imap->sock, "UID FETCH %d RFC822.PEEK", uid);
for (;;)
{
@@ -477,7 +575,7 @@ imap_fetch_message (imap_t * imap, unsigned int uid, int fd)
n = bytes;
if (n > sizeof (buf))
n = sizeof (buf);
- n = read (imap->fd, buf, n);
+ n = socket_read (imap->sock, buf, n);
if (n > 0)
{
// printf("imap_fetch_message:%d:read %d bytes\n", __LINE__, n);
diff --git a/isync.1 b/isync.1
@@ -115,7 +115,19 @@ command, apply to this mailbox only.
..
.TP
\fBHost\fR \fIname\fR
-Defines the DNS name or IP address of the IMAP server
+Defines the DNS name or IP address of the IMAP server. If the hostname is
+prefixed with
+.I imaps:
+the connection is assumed to be a SSL connection to port 993 (though you can
+change this by placing a
+.B Port
+command
+.B after
+the
+.B Host
+command. Note that some servers support SSL on the default port 143.
+.B isync
+will always attempt to use SSL if available.
..
.TP
\fBPort\fR \fIport\fR
@@ -144,6 +156,18 @@ will prompt you for it.
\fBAlias\fR \fIstring\fR
Defines an alias for the mailbox which can be used as a shortcut on the
command line.
+..
+.TP
+\fBRequireSSL\fR \fIyes|no\fR
+.B isync will abort the connection if a TLS/SSL session to the IMAP
+server can not be established. (Default:
+.I yes
+)
+..
+.TP
+\fBCertificateFile\fR \fIpath\fR
+File containing X.509 CA certificates used to verify server identities.
+..
.P
Configuration commands that appear prior to the first
.B Mailbox
@@ -176,9 +200,3 @@ http://www.sigpipe.org/isync/.
..
.SH AUTHOR
Written by Michael R. Elkins <me@mutt.org>.
-..
-.SH BUGS
-SSL is currently not used when connecting to the IMAP server. A future
-version of
-.B isync
-is expected to support this.
diff --git a/isync.h b/isync.h
@@ -19,10 +19,22 @@
*/
#include <stdarg.h>
+#if HAVE_LIBSSL
+#include <openssl/ssl.h>
+#endif
typedef struct
{
int fd;
+#if HAVE_LIBSSL
+ SSL *ssl;
+ unsigned int use_ssl:1;
+#endif
+} Socket_t;
+
+typedef struct
+{
+ Socket_t *sock;
char buf[1024];
int bytes;
int offset;
@@ -43,6 +55,11 @@ struct config
char *box;
char *alias;
config_t *next;
+#if HAVE_LIBSSL
+ char *cert_file;
+ unsigned int use_imaps:1;
+ unsigned int require_ssl:1;
+#endif
};
/* struct representing local mailbox file */
@@ -78,7 +95,7 @@ struct message
/* imap connection info */
typedef struct
{
- int fd; /* server socket */
+ Socket_t *sock;
unsigned int count; /* # of msgs */
unsigned int recent; /* # of recent messages */
buffer_t *buf; /* input buffer for reading server output */
@@ -101,6 +118,10 @@ extern unsigned int Tag;
extern char Hostname[256];
extern int Verbose;
+#if HAVE_LIBSSL
+extern SSL_CTX *SSLContext;
+#endif
+
char *next_arg (char **);
int sync_mailbox (mailbox_t *, imap_t *, int);
diff --git a/main.c b/main.c
@@ -107,6 +107,22 @@ enter_password (void)
return strdup (pass);
}
+/* set defaults from the global configuration section */
+static void
+config_defaults (config_t * conf)
+{
+ conf->user = global.user;
+ conf->pass = global.pass;
+ conf->port = global.port;
+ conf->box = global.box;
+ conf->host = global.host;
+#if HAVE_LIBSSL
+ conf->require_ssl = global.require_ssl;
+ conf->use_imaps = global.use_imaps;
+ conf->cert_file = global.cert_file;
+#endif
+}
+
static void
load_config (char *where)
{
@@ -152,10 +168,25 @@ load_config (char *where)
if (*cur)
cur = &(*cur)->next;
*cur = calloc (1, sizeof (config_t));
+ config_defaults (*cur);
(*cur)->path = strdup (p);
}
else if (!strncasecmp ("host", buf, 4))
{
+ if (!strncasecmp ("imaps:", p, 6))
+ {
+ p += 6;
+ if (*cur)
+ {
+ (*cur)->use_imaps = 1;
+ (*cur)->port = 993;
+ }
+ else
+ {
+ global.use_imaps = 1;
+ global.port = 993;
+ }
+ }
if (*cur)
(*cur)->host = strdup (p);
else
@@ -194,6 +225,22 @@ load_config (char *where)
if (*cur)
(*cur)->alias = strdup (p);
}
+#if HAVE_LIBSSL
+ else if (!strncasecmp ("CertificateFile", buf, 15))
+ {
+ if (*cur)
+ (*cur)->cert_file = strdup (p);
+ else
+ global.cert_file = strdup (p);
+ }
+ else if (!strncasecmp ("RequireSSL", buf, 10))
+ {
+ if (*cur)
+ (*cur)->require_ssl = (strcasecmp (p, "yes") == 0);
+ else
+ global.require_ssl = (strcasecmp (p, "yes") == 0);
+ }
+#endif
else if (buf[0])
printf ("%s:%d:unknown command:%s", path, line, buf);
}
@@ -257,6 +304,12 @@ main (int argc, char **argv)
global.port = 143;
global.box = "INBOX";
global.user = strdup (pw->pw_name);
+#if HAVE_LIBSSL
+ /* this will probably annoy people, but its the best default just in
+ * case people forget to turn it on
+ */
+ global.require_ssl = 1;
+#endif
#if HAVE_GETOPT_LONG
while ((i = getopt_long (argc, argv, "defhp:u:r:s:vV", Opts, NULL)) != -1)
@@ -326,29 +379,15 @@ main (int argc, char **argv)
box = &global;
}
- /* fill in missing info with defaults */
if (!box->pass)
{
- if (!global.pass)
+ box->pass = enter_password ();
+ if (!box->pass)
{
- box->pass = enter_password ();
- if (!box->pass)
- {
- puts ("Aborting, no password");
- exit (1);
- }
+ puts ("Aborting, no password");
+ exit (1);
}
- else
- box->pass = global.pass;
}
- if (!box->user)
- box->user = global.user;
- if (!box->port)
- box->port = global.port;
- if (!box->host)
- box->host = global.host;
- if (!box->box)
- box->box = global.box;
printf ("Reading %s\n", box->path);
mail = maildir_open (box->path, fast);