Browse Source

added OpenSSL support

0.9
Michael Elkins 24 years ago
parent
commit
b6089a2dcb
  1. 2
      configure.in
  2. 118
      imap.c
  3. 32
      isync.1
  4. 23
      isync.h
  5. 75
      main.c

2
configure.in

@ -5,5 +5,7 @@ if test $CC = gcc; then
CFLAGS="$CFLAGS -pipe" CFLAGS="$CFLAGS -pipe"
fi fi
AC_CHECK_FUNCS(getopt_long) 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" CFLAGS="$CFLAGS -W -Wall -pedantic -Wmissing-prototypes -Wmissing-declarations"
AC_OUTPUT(Makefile) AC_OUTPUT(Makefile)

118
imap.c

@ -29,6 +29,9 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
#if HAVE_LIBSSL
#include <openssl/err.h>
#endif
#include "isync.h" #include "isync.h"
const char *Flags[] = { const char *Flags[] = {
@ -40,6 +43,56 @@ const char *Flags[] = {
"\\Draft" "\\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 */ /* simple line buffering */
static int static int
buffer_gets (buffer_t * b, char **s) buffer_gets (buffer_t * b, char **s)
@ -64,7 +117,10 @@ buffer_gets (buffer_t * b, char **s)
b->offset = n; b->offset = n;
start = 0; 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 <= 0)
{ {
if (n == -1) 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); snprintf (buf, sizeof (buf), "%d %s\r\n", ++Tag, tmp);
if (Verbose) if (Verbose)
fputs (buf, stdout); fputs (buf, stdout);
write (imap->fd, buf, strlen (buf)); socket_write (imap->sock, buf, strlen (buf));
for (;;) for (;;)
{ {
@ -223,7 +279,6 @@ imap_exec (imap_t * imap, const char *fmt, ...)
arg = next_arg (&cmd); arg = next_arg (&cmd);
if (!strcmp ("OK", arg)) if (!strcmp ("OK", arg))
return 0; return 0;
puts ("IMAP command failed");
return -1; return -1;
} }
} }
@ -289,6 +344,15 @@ imap_open (config_t * box, int fast)
int s; int s;
struct sockaddr_in sin; struct sockaddr_in sin;
struct hostent *he; 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 */ /* open connection to IMAP server */
@ -321,12 +385,46 @@ imap_open (config_t * box, int fast)
puts ("ok"); puts ("ok");
imap = calloc (1, sizeof (imap_t)); imap = calloc (1, sizeof (imap_t));
imap->fd = s; imap->sock = calloc (1, sizeof (Socket_t));
//imap->state = imap_state_init; imap->sock->fd = s;
imap->buf = calloc (1, sizeof (buffer_t)); imap->buf = calloc (1, sizeof (buffer_t));
imap->buf->fd = s; imap->buf->sock = imap->sock;
imap->box = box; 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..."); puts ("Logging in...");
ret = imap_exec (imap, "LOGIN %s %s", box->user, box->pass); ret = imap_exec (imap, "LOGIN %s %s", box->user, box->pass);
if (!ret) if (!ret)
@ -395,7 +493,7 @@ write_strip (int fd, char *buf, size_t len)
} }
static void static void
send_server (int fd, const char *fmt, ...) send_server (Socket_t * sock, const char *fmt, ...)
{ {
char buf[128]; char buf[128];
char cmd[128]; char cmd[128];
@ -406,7 +504,7 @@ send_server (int fd, const char *fmt, ...)
va_end (ap); va_end (ap);
snprintf (cmd, sizeof (cmd), "%d %s\r\n", ++Tag, buf); snprintf (cmd, sizeof (cmd), "%d %s\r\n", ++Tag, buf);
write (fd, cmd, strlen (cmd)); socket_write (sock, cmd, strlen (cmd));
if (Verbose) if (Verbose)
fputs (cmd, stdout); fputs (cmd, stdout);
@ -421,7 +519,7 @@ imap_fetch_message (imap_t * imap, unsigned int uid, int fd)
size_t n; size_t n;
char buf[1024]; char buf[1024];
send_server (imap->fd, "UID FETCH %d RFC822.PEEK", uid); send_server (imap->sock, "UID FETCH %d RFC822.PEEK", uid);
for (;;) for (;;)
{ {
@ -477,7 +575,7 @@ imap_fetch_message (imap_t * imap, unsigned int uid, int fd)
n = bytes; n = bytes;
if (n > sizeof (buf)) if (n > sizeof (buf))
n = sizeof (buf); n = sizeof (buf);
n = read (imap->fd, buf, n); n = socket_read (imap->sock, buf, n);
if (n > 0) if (n > 0)
{ {
// printf("imap_fetch_message:%d:read %d bytes\n", __LINE__, n); // printf("imap_fetch_message:%d:read %d bytes\n", __LINE__, n);

32
isync.1

@ -115,7 +115,19 @@ command, apply to this mailbox only.
.. ..
.TP .TP
\fBHost\fR \fIname\fR \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 .TP
\fBPort\fR \fIport\fR \fBPort\fR \fIport\fR
@ -144,6 +156,18 @@ will prompt you for it.
\fBAlias\fR \fIstring\fR \fBAlias\fR \fIstring\fR
Defines an alias for the mailbox which can be used as a shortcut on the Defines an alias for the mailbox which can be used as a shortcut on the
command line. 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 .P
Configuration commands that appear prior to the first Configuration commands that appear prior to the first
.B Mailbox .B Mailbox
@ -176,9 +200,3 @@ http://www.sigpipe.org/isync/.
.. ..
.SH AUTHOR .SH AUTHOR
Written by Michael R. Elkins <me@mutt.org>. 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.

23
isync.h

@ -19,10 +19,22 @@
*/ */
#include <stdarg.h> #include <stdarg.h>
#if HAVE_LIBSSL
#include <openssl/ssl.h>
#endif
typedef struct typedef struct
{ {
int fd; int fd;
#if HAVE_LIBSSL
SSL *ssl;
unsigned int use_ssl:1;
#endif
} Socket_t;
typedef struct
{
Socket_t *sock;
char buf[1024]; char buf[1024];
int bytes; int bytes;
int offset; int offset;
@ -43,6 +55,11 @@ struct config
char *box; char *box;
char *alias; char *alias;
config_t *next; 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 */ /* struct representing local mailbox file */
@ -78,7 +95,7 @@ struct message
/* imap connection info */ /* imap connection info */
typedef struct typedef struct
{ {
int fd; /* server socket */ Socket_t *sock;
unsigned int count; /* # of msgs */ unsigned int count; /* # of msgs */
unsigned int recent; /* # of recent messages */ unsigned int recent; /* # of recent messages */
buffer_t *buf; /* input buffer for reading server output */ buffer_t *buf; /* input buffer for reading server output */
@ -101,6 +118,10 @@ extern unsigned int Tag;
extern char Hostname[256]; extern char Hostname[256];
extern int Verbose; extern int Verbose;
#if HAVE_LIBSSL
extern SSL_CTX *SSLContext;
#endif
char *next_arg (char **); char *next_arg (char **);
int sync_mailbox (mailbox_t *, imap_t *, int); int sync_mailbox (mailbox_t *, imap_t *, int);

75
main.c

@ -107,6 +107,22 @@ enter_password (void)
return strdup (pass); 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 static void
load_config (char *where) load_config (char *where)
{ {
@ -152,10 +168,25 @@ load_config (char *where)
if (*cur) if (*cur)
cur = &(*cur)->next; cur = &(*cur)->next;
*cur = calloc (1, sizeof (config_t)); *cur = calloc (1, sizeof (config_t));
config_defaults (*cur);
(*cur)->path = strdup (p); (*cur)->path = strdup (p);
} }
else if (!strncasecmp ("host", buf, 4)) 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) if (*cur)
(*cur)->host = strdup (p); (*cur)->host = strdup (p);
else else
@ -194,6 +225,22 @@ load_config (char *where)
if (*cur) if (*cur)
(*cur)->alias = strdup (p); (*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]) else if (buf[0])
printf ("%s:%d:unknown command:%s", path, line, buf); printf ("%s:%d:unknown command:%s", path, line, buf);
} }
@ -257,6 +304,12 @@ main (int argc, char **argv)
global.port = 143; global.port = 143;
global.box = "INBOX"; global.box = "INBOX";
global.user = strdup (pw->pw_name); 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 #if HAVE_GETOPT_LONG
while ((i = getopt_long (argc, argv, "defhp:u:r:s:vV", Opts, NULL)) != -1) 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; box = &global;
} }
/* fill in missing info with defaults */
if (!box->pass) if (!box->pass)
{ {
if (!global.pass) box->pass = enter_password ();
if (!box->pass)
{ {
box->pass = enter_password (); puts ("Aborting, no password");
if (!box->pass) 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); printf ("Reading %s\n", box->path);
mail = maildir_open (box->path, fast); mail = maildir_open (box->path, fast);

Loading…
Cancel
Save