Skipped 4 existing revision(s) on branch 'master'.
commit b730f66f7d29433ec5c94936ce408f2ea498fbea (from
9a4be0af5f37aeceb4e2ac807f5e6242b3ddc515)
Merge: 9a4be0a 2fa75cf
Author: Oswald Buddenhagen <[email protected]>
Date: Sun Jan 11 14:32:15 2015 +0100
Merge branch 'isync_1_1_branch' into HEAD
Conflicts:
src/socket.c
src/driver.h | 2 +-
src/drv_imap.c | 21 ++++++++++++++-------
src/drv_maildir.c | 2 +-
src/main.c | 8 ++++++--
src/socket.c | 8 ++++----
src/socket.h | 3 ++-
src/sync.c | 8 +++++---
7 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/src/driver.h b/src/driver.h
index d525f55..5adbc84 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -191,7 +191,7 @@ struct driver {
/* Index the messages which have newly appeared in the mailbox,
including their
* temporary UID headers. This is needed if store_msg() does not
guarantee returning
* a UID; otherwise the driver needs to implement only the OPEN_FIND
flag. */
- void (*find_new_msgs)( store_t *ctx,
+ void (*find_new_msgs)( store_t *ctx, int newuid,
void (*cb)( int sts, void *aux ), void *aux );
/* Add/remove the named flags to/from the given message. The message
may be either
diff --git a/src/drv_imap.c b/src/drv_imap.c
index 21499c8..990d325 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -166,6 +166,11 @@ struct imap_cmd_out_uid {
int out_uid;
};
+struct imap_cmd_find_new {
+ struct imap_cmd_simple gen;
+ int uid;
+};
+
struct imap_cmd_refcounted_state {
void (*callback)( int sts, void *aux );
void *callback_aux;
@@ -2392,28 +2397,30 @@ imap_store_msg_p2( imap_store_t *ctx ATTR_UNUSED,
struct imap_cmd *cmd, int resp
static void imap_find_new_msgs_p2( imap_store_t *, struct imap_cmd *, int );
static void
-imap_find_new_msgs( store_t *gctx,
+imap_find_new_msgs( store_t *gctx, int newuid,
void (*cb)( int sts, void *aux ), void *aux )
{
imap_store_t *ctx = (imap_store_t *)gctx;
- struct imap_cmd_simple *cmd;
+ struct imap_cmd_find_new *cmd;
- INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
- imap_exec( (imap_store_t *)ctx, &cmd->gen, imap_find_new_msgs_p2,
"CHECK" );
+ INIT_IMAP_CMD_X(imap_cmd_find_new, cmd, cb, aux)
+ cmd->uid = newuid;
+ imap_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_find_new_msgs_p2,
"CHECK" );
}
static void
imap_find_new_msgs_p2( imap_store_t *ctx, struct imap_cmd *gcmd, int response )
{
- struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)gcmd, *cmd;
+ struct imap_cmd_find_new *cmdp = (struct imap_cmd_find_new *)gcmd;
+ struct imap_cmd_simple *cmd;
if (response != RESP_OK) {
imap_done_simple_box( ctx, gcmd, response );
return;
}
- INIT_IMAP_CMD(imap_cmd_simple, cmd, cmdp->callback, cmdp->callback_aux)
+ INIT_IMAP_CMD(imap_cmd_simple, cmd, cmdp->gen.callback,
cmdp->gen.callback_aux)
imap_exec( (imap_store_t *)ctx, &cmd->gen, imap_done_simple_box,
- "UID FETCH %d:1000000000 (UID BODY.PEEK[HEADER.FIELDS
(X-TUID)])", ctx->gen.uidnext );
+ "UID FETCH %d:1000000000 (UID BODY.PEEK[HEADER.FIELDS
(X-TUID)])", cmdp->uid );
}
/******************* imap_list *******************/
diff --git a/src/drv_maildir.c b/src/drv_maildir.c
index 5bf88c1..fc73f7b 100644
--- a/src/drv_maildir.c
+++ b/src/drv_maildir.c
@@ -1295,7 +1295,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int
to_trash,
}
static void
-maildir_find_new_msgs( store_t *gctx ATTR_UNUSED,
+maildir_find_new_msgs( store_t *gctx ATTR_UNUSED, int newuid ATTR_UNUSED,
void (*cb)( int sts, void *aux ) ATTR_UNUSED, void *aux
ATTR_UNUSED )
{
assert( !"maildir_find_new_msgs is not supposed to be called" );
diff --git a/src/main.c b/src/main.c
index bb8fc36..0ff9ec8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -598,12 +598,16 @@ sync_chans( main_vars_t *mvars, int ent )
labels[M] = "M: ", labels[S] = "S: ";
else
labels[M] = labels[S] = "";
- for (t = 0; t < 2; t++) {
+ for (t = 0; ; t++) {
info( "Opening %s %s...\n", str_ms[t],
mvars->chan->stores[t]->name );
mvars->drv[t] = mvars->chan->stores[t]->driver;
mvars->drv[t]->open_store( mvars->chan->stores[t],
labels[t], store_opened, AUX );
- if (mvars->skip)
+ if (t)
break;
+ if (mvars->skip) {
+ mvars->state[1] = ST_CLOSED;
+ break;
+ }
}
mvars->cben = 1;
opened:
diff --git a/src/socket.c b/src/socket.c
index 23a2eb8..0108243 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -154,7 +154,7 @@ verify_hostname( X509 *cert, const char *hostname )
static int
verify_cert_host( const server_conf_t *conf, conn_t *sock )
{
- unsigned i;
+ int i;
long err;
X509 *cert;
STACK_OF(X509_OBJECT) *trusted;
@@ -165,8 +165,8 @@ verify_cert_host( const server_conf_t *conf, conn_t *sock )
return -1;
}
- trusted = SSL_CTX_get_cert_store( conf->SSLContext )->objs;
- for (i = 0; i < conf->num_trusted; i++) {
+ trusted = (STACK_OF(X509_OBJECT) *)sock->conf->trusted_certs;
+ for (i = 0; i < sk_X509_OBJECT_num( trusted ); i++) {
if (!X509_cmp( cert, sk_X509_OBJECT_value( trusted, i
)->data.x509 ))
return 0;
}
@@ -218,7 +218,7 @@ init_ssl_ctx( const server_conf_t *conf )
conf->cert_file, ERR_error_string( ERR_get_error(), 0 )
);
return 0;
}
- mconf->num_trusted = sk_X509_OBJECT_num( SSL_CTX_get_cert_store(
mconf->SSLContext )->objs );
+ mconf->trusted_certs = (_STACK *)sk_X509_OBJECT_dup(
SSL_CTX_get_cert_store( mconf->SSLContext )->objs );
if (mconf->system_certs && !SSL_CTX_set_default_verify_paths(
mconf->SSLContext ))
warn( "Warning: Unable to load default certificate files: %s\n",
ERR_error_string( ERR_get_error(), 0 ) );
diff --git a/src/socket.h b/src/socket.h
index 5a6a3cd..e09a9e1 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -28,6 +28,7 @@
#ifdef HAVE_LIBSSL
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef struct stack_st _STACK;
enum {
SSLv2 = 1,
@@ -49,7 +50,7 @@ typedef struct server_conf {
/* these are actually variables and are leaked at the end */
char ssl_ctx_valid;
- unsigned num_trusted;
+ _STACK *trusted_certs;
SSL_CTX *SSLContext;
#endif
} server_conf_t;
diff --git a/src/sync.c b/src/sync.c
index 4a4c913..e222f6f 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -498,11 +498,12 @@ cancel_done( void *aux )
svars->state[t] |= ST_CANCELED;
if (svars->state[1-t] & ST_CANCELED) {
- if (svars->lfd) {
+ if (svars->lfd >= 0) {
Fclose( svars->nfp, 0 );
Fclose( svars->jfp, 0 );
sync_bail( svars );
} else {
+ /* Early failure during box selection. */
sync_bail2( svars );
}
}
@@ -1507,7 +1508,8 @@ box_loaded( int sts, void *aux )
if (UseFSync)
fdatasync( fileno( svars->jfp ) );
for (t = 0; t < 2; t++) {
- Fprintf( svars->jfp, "%c %d\n", "{}"[t], svars->ctx[t]->uidnext
);
+ svars->newuid[t] = svars->ctx[t]->uidnext;
+ Fprintf( svars->jfp, "%c %d\n", "{}"[t], svars->newuid[t] );
for (tmsg = svars->ctx[1-t]->msgs; tmsg; tmsg = tmsg->next) {
if ((srec = tmsg->srec) && srec->tuid[0]) {
svars->new_total[t]++;
@@ -1605,7 +1607,7 @@ msgs_copied( sync_vars_t *svars, int t )
if (svars->state[t] & ST_FIND_NEW) {
debug( "finding just copied messages on %s\n", str_ms[t] );
- svars->drv[t]->find_new_msgs( svars->ctx[t], msgs_found_new,
AUX );
+ svars->drv[t]->find_new_msgs( svars->ctx[t], svars->newuid[t],
msgs_found_new, AUX );
} else {
msgs_new_done( svars, t );
}
commit b730f66f7d29433ec5c94936ce408f2ea498fbea (from
2fa75cf159d18c5705a877690b62f9e5de160c81)
Merge: 9a4be0a 2fa75cf
Author: Oswald Buddenhagen <[email protected]>
AuthorDate: Sun Jan 11 14:32:15 2015 +0100
Commit: Oswald Buddenhagen <[email protected]>
CommitDate: Sun Jan 11 14:32:15 2015 +0100
Merge branch 'isync_1_1_branch' into HEAD
Conflicts:
src/socket.c
---
Makefile.am | 2 +-
NEWS | 12 +
README | 5 +-
TODO | 4 -
configure.ac | 56 ++++-
src/Makefile.am | 2 +-
src/common.h | 1 +
src/compat/isync.1 | 3 +
src/compat/main.c | 3 +
src/config.c | 18 ++-
src/config.h | 5 +
src/driver.h | 1 -
src/drv_imap.c | 558 ++++++++++++++++++++++++++++++++++---------
src/drv_maildir.c | 53 +++--
src/main.c | 5 +
src/mbsync.1 | 108 +++++----
src/socket.c | 139 +++---------
src/socket.h | 18 +-
src/sync.c | 20 +-
19 files changed, 687 insertions(+), 326 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 5141f7c..b47edf6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,7 +51,7 @@ $(srcdir)/ChangeLog: log
log:
@test -z "$(srcdir)" || cd $(srcdir) && \
( ! test -d .git || \
- git log --date=iso --log-size --name-only | \
+ git log --date=iso --log-size --name-only --no-merges | \
perl -e '$(LOG_PL)' > ChangeLog )
deb: deb-clean
diff --git a/NEWS b/NEWS
index dd69fba..d84eb62 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,15 @@
+[1.2.0]
+
+The 'isync' compatibility wrapper is now deprecated.
+
+The SSL/TLS configuration has been re-designed.
+SSL is now explicitly enabled or disabled - "use SSL if available" is gone.
+Notice: Tunnels are assumed to be secure and thus default to no SSL.
+
+Support for SASL (flexible authentication) has been added.
+
+Support for Windows file systems has been added.
+
[1.1.0]
Support for hierarchical mailboxes in Patterns.
diff --git a/README b/README
index 2c634e5..66a0017 100644
--- a/README
+++ b/README
@@ -32,7 +32,7 @@ isync executable still exists; it is a compatibility wrapper
around mbsync.
* Trash functionality: backup messages before removing them
* IMAP features:
* Supports TLS/SSL via imaps: (port 993) and STARTTLS (RFC2595)
- * Supports CRAM-MD5 (RFC2195) for authentication
+ * Supports SASL (RFC4422) for authentication
* Supports NAMESPACE (RFC2342) for simplified configuration
* Pipelining for maximum speed
@@ -59,9 +59,6 @@ isync executable still exists; it is a compatibility wrapper
around mbsync.
At some point, ``isync'' has successfully run on:
Linux, Solaris 2.7, OpenBSD 2.8, FreeBSD 4.3.
- Note that Cygwin cannot be reasonably supported due to restrictions
- of the Windows file system.
-
* Requirements
Berkley DB 4.2+
diff --git a/TODO b/TODO
index ba556f9..02d80b4 100644
--- a/TODO
+++ b/TODO
@@ -6,10 +6,6 @@ real transactions would be certainly not particularly useful
...
make sync_chans() aware of servers, so a bad server (e.g., wrong password)
won't cause the same error message for every attached store.
-add support for more authentication methods: oauth, ntlm, ... use SASL?
-possibly by calling an external command. that might be overkill, and
-wouldn't be very user-friendly, though.
-
make SSL (connect) timeouts produce a bit more than "Unidentified socket
error".
network timeout handling in general would be a good idea.
diff --git a/configure.ac b/configure.ac
index f6d5d64..ac696ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([isync], [1.1.2])
+AC_INIT([isync], [1.2.0])
AC_CONFIG_HEADERS([autodefs.h])
AM_INIT_AUTOMAKE
@@ -100,6 +100,45 @@ if test "x$ob_cv_with_ssl" != xno; then
fi
AC_SUBST(SSL_LIBS)
+have_sasl_paths=
+AC_ARG_WITH(sasl,
+ AS_HELP_STRING([--with-sasl[=PATH]], [where to look for SASL [detect]]),
+ [ob_cv_with_sasl=$withval])
+if test "x$ob_cv_with_sasl" != xno; then
+ case $ob_cv_with_sasl in
+ ""|yes)
+ dnl FIXME: Try various possible paths here...
+ ;;
+ *)
+ SASL_LDFLAGS=-L$ob_cv_with_sasl/lib$libsuff
+ SASL_CPPFLAGS=-I$ob_cv_with_sasl/include
+ ;;
+ esac
+ if test -z "$have_sasl_paths"; then
+ sav_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS $SASL_LDFLAGS"
+ AC_CHECK_LIB(sasl2, sasl_client_init,
+ [SASL_LIBS="-lsasl2" have_sasl_paths=yes])
+ LDFLAGS=$sav_LDFLAGS
+ fi
+
+ sav_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $SASL_CPPFLAGS"
+ AC_CHECK_HEADER(sasl/sasl.h, , [have_sasl_paths=])
+ CPPFLAGS=$sav_CPPFLAGS
+
+ if test -z "$have_sasl_paths"; then
+ if test -n "$ob_cv_with_sasl"; then
+ AC_MSG_ERROR([SASL libs and/or includes were not found where specified])
+ fi
+ else
+ AC_DEFINE(HAVE_LIBSASL, 1, [if you have the SASL libraries])
+ CPPFLAGS="$CPPFLAGS $SASL_CPPFLAGS"
+ LDFLAGS="$LDFLAGS $SASL_LDFLAGS"
+ fi
+fi
+AC_SUBST(SASL_LIBS)
+
AC_CACHE_CHECK([for Berkley DB >= 4.2], ac_cv_berkdb4,
[ac_cv_berkdb4=no
AC_TRY_LINK([#include <db.h>],
@@ -122,12 +161,15 @@ AM_CONDITIONAL(with_compat, test "x$ob_cv_enable_compat"
!= xno)
AC_CONFIG_FILES([Makefile src/Makefile src/compat/Makefile isync.spec])
AC_OUTPUT
+AC_MSG_RESULT()
if test -n "$have_ssl_paths"; then
- AC_MSG_RESULT([
-Using SSL
-])
+ AC_MSG_RESULT([Using SSL])
+else
+ AC_MSG_RESULT([Not using SSL])
+fi
+if test -n "$have_sasl_paths"; then
+ AC_MSG_RESULT([Using SASL])
else
- AC_MSG_RESULT([
-Not using SSL
-])
+ AC_MSG_RESULT([Not using SASL])
fi
+AC_MSG_RESULT()
diff --git a/src/Makefile.am b/src/Makefile.am
index 9cfd0af..85d5bab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,7 +6,7 @@ SUBDIRS = $(compat_dir)
bin_PROGRAMS = mbsync mdconvert
mbsync_SOURCES = main.c sync.c config.c util.c socket.c driver.c drv_imap.c
drv_maildir.c
-mbsync_LDADD = -ldb $(SSL_LIBS) $(SOCK_LIBS)
+mbsync_LDADD = -ldb $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS)
noinst_HEADERS = common.h config.h driver.h sync.h socket.h
mdconvert_SOURCES = mdconvert.c
diff --git a/src/common.h b/src/common.h
index e90f0ea..41067a0 100644
--- a/src/common.h
+++ b/src/common.h
@@ -65,6 +65,7 @@
extern int DFlags;
extern int UseFSync;
+extern char FieldDelimiter;
extern int Pid;
extern char Hostname[256];
diff --git a/src/compat/isync.1 b/src/compat/isync.1
index c8ed9f3..527ca6a 100644
--- a/src/compat/isync.1
+++ b/src/compat/isync.1
@@ -37,6 +37,9 @@ It will automatically migrate the UID mapping from previous
versions of
\fBmbsync\fR. If you were using \fBisync\fR version 0.8 or 0.9.x you might
want to use \fBmdconvert\fR to convert the mailboxes to the more efficient
\fBnative\fR UID storage scheme after migrating them.
+.br
+\fBisync\fR is deprecated. Please use the \fB-w\fR option to permanently
+migrate the configuration and start using \fBmbsync\fR directly.
..
.SH OPTIONS
.TP
diff --git a/src/compat/main.c b/src/compat/main.c
index b8cc976..2ad6f07 100644
--- a/src/compat/main.c
+++ b/src/compat/main.c
@@ -288,6 +288,9 @@ main( int argc, char **argv )
}
}
+ if (!writeout)
+ fputs( "Notice: please run 'isync -w' and start using 'mbsync'
directly.\n", stderr );
+
if (config) {
if (*config != '/') {
if (!getcwd( path1, sizeof(path1) )) {
diff --git a/src/config.c b/src/config.c
index cf3b165..49c620c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -36,10 +36,7 @@
store_conf_t *stores;
-#define ARG_OPTIONAL 0
-#define ARG_REQUIRED 1
-
-static char *
+char *
get_arg( conffile_t *cfile, int required, int *comment )
{
char *ret, *p, *t;
@@ -470,6 +467,19 @@ load_config( const char *where, int pseudo )
{
UseFSync = parse_bool( &cfile );
}
+ else if (!strcasecmp( "FieldDelimiter", cfile.cmd ))
+ {
+ if (strlen( cfile.val ) != 1) {
+ error( "%s:%d: Field delimiter must be exactly
one character long\n", cfile.file, cfile.line );
+ cfile.err = 1;
+ } else {
+ FieldDelimiter = cfile.val[0];
+ if (!ispunct( FieldDelimiter )) {
+ error( "%s:%d: Field delimiter must be
a punctuation character\n", cfile.file, cfile.line );
+ cfile.err = 1;
+ }
+ }
+ }
else if (!getopt_helper( &cfile, &gcops, &global_conf ))
{
error( "%s:%d: unknown section keyword '%s'\n",
diff --git a/src/config.h b/src/config.h
index b9b4bfe..e3bc72f 100644
--- a/src/config.h
+++ b/src/config.h
@@ -35,6 +35,11 @@ typedef struct conffile {
char *cmd, *val, *rest;
} conffile_t;
+#define ARG_OPTIONAL 0
+#define ARG_REQUIRED 1
+
+char *get_arg( conffile_t *cfile, int required, int *comment );
+
int parse_bool( conffile_t *cfile );
int parse_int( conffile_t *cfile );
int parse_size( conffile_t *cfile );
diff --git a/src/driver.h b/src/driver.h
index 4557aa6..5adbc84 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -86,7 +86,6 @@ typedef struct store {
void *bad_callback_aux;
/* currently open mailbox */
- const char *orig_name; /* foreign! maybe preset? */
char *path; /* own */
message_t *msgs; /* own */
int uidvalidity;
diff --git a/src/drv_imap.c b/src/drv_imap.c
index f58736d..990d325 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -36,6 +36,15 @@
#include <time.h>
#include <sys/wait.h>
+#ifdef HAVE_LIBSASL
+# include <sasl/sasl.h>
+# include <sasl/saslutil.h>
+#endif
+
+#ifdef HAVE_LIBSSL
+enum { SSL_None, SSL_STARTTLS, SSL_IMAPS };
+#endif
+
typedef struct imap_server_conf {
struct imap_server_conf *next;
char *name;
@@ -44,10 +53,9 @@ typedef struct imap_server_conf {
char *pass;
char *pass_cmd;
int max_in_progress;
+ string_list_t *auth_mechs;
#ifdef HAVE_LIBSSL
- char use_ssl;
- char require_ssl;
- char require_cram;
+ char ssl_type;
#endif
} imap_server_conf_t;
@@ -97,6 +105,7 @@ typedef struct imap_store {
list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
message_t **msgapp; /* FETCH results */
unsigned caps; /* CAPABILITY results */
+ string_list_t *auth_mechs;
parse_list_state_t parse_list_sts;
/* command queue */
int nexttag, num_in_progress;
@@ -111,6 +120,10 @@ typedef struct imap_store {
void (*imap_cancel)( void *aux );
} callbacks;
void *callback_aux;
+#ifdef HAVE_LIBSASL
+ sasl_conn_t *sasl;
+ int sasl_cont;
+#endif
conn_t conn; /* this is BIG, so put it last */
} imap_store_t;
@@ -174,8 +187,10 @@ struct imap_cmd_refcounted {
enum CAPABILITY {
NOLOGIN = 0,
+#ifdef HAVE_LIBSASL
+ SASLIR,
+#endif
#ifdef HAVE_LIBSSL
- CRAM,
STARTTLS,
#endif
UIDPLUS,
@@ -186,8 +201,10 @@ enum CAPABILITY {
static const char *cap_list[] = {
"LOGINDISABLED",
+#ifdef HAVE_LIBSASL
+ "SASL-IR",
+#endif
#ifdef HAVE_LIBSSL
- "AUTH=CRAM-MD5",
"STARTTLS",
#endif
"UIDPLUS",
@@ -985,11 +1002,20 @@ parse_capability( imap_store_t *ctx, char *cmd )
char *arg;
unsigned i;
+ free_string_list( ctx->auth_mechs );
+ ctx->auth_mechs = 0;
ctx->caps = 0x80000000;
- while ((arg = next_arg( &cmd )))
- for (i = 0; i < as(cap_list); i++)
- if (!strcmp( cap_list[i], arg ))
- ctx->caps |= 1 << i;
+ while ((arg = next_arg( &cmd ))) {
+ if (starts_with( arg, -1, "AUTH=", 5 )) {
+ add_string_list( &ctx->auth_mechs, arg + 5 );
+ } else {
+ for (i = 0; i < as(cap_list); i++)
+ if (!strcmp( cap_list[i], arg ))
+ ctx->caps |= 1 << i;
+ }
+ }
+ if (!CAP(NOLOGIN))
+ add_string_list( &ctx->auth_mechs, "LOGIN" );
}
static int
@@ -1249,7 +1275,8 @@ imap_socket_read( void *aux )
ctx->trashnc = TrashKnown; /* Can't get
NO [TRYCREATE] any more. */
p = cmdp->param.data;
cmdp->param.data = 0;
- if (socket_write( &ctx->conn, p,
cmdp->param.data_len, GiveOwn ) < 0)
+ if (socket_write( &ctx->conn, p,
cmdp->param.data_len, GiveOwn ) < 0 ||
+ socket_write( &ctx->conn, "\r\n", 2,
KeepOwn ) < 0)
return;
} else if (cmdp->param.cont) {
if (cmdp->param.cont( ctx, cmdp, cmd ))
@@ -1258,8 +1285,6 @@ imap_socket_read( void *aux )
error( "IMAP error: unexpected command
continuation request\n" );
break;
}
- if (socket_write( &ctx->conn, "\r\n", 2, KeepOwn ) < 0)
- return;
} else {
tag = atoi( arg );
for (pcmdp = &ctx->in_progress; (cmdp = *pcmdp); pcmdp
= &cmdp->next)
@@ -1348,6 +1373,9 @@ imap_cancel_store( store_t *gctx )
{
imap_store_t *ctx = (imap_store_t *)gctx;
+#ifdef HAVE_LIBSASL
+ sasl_dispose( &ctx->sasl );
+#endif
socket_close( &ctx->conn );
cancel_submitted_imap_cmds( ctx );
cancel_pending_imap_cmds( ctx );
@@ -1356,6 +1384,7 @@ imap_cancel_store( store_t *gctx )
free_list( ctx->ns_personal );
free_list( ctx->ns_other );
free_list( ctx->ns_shared );
+ free_string_list( ctx->auth_mechs );
free( ctx->delimiter );
imap_deref( ctx );
}
@@ -1429,28 +1458,6 @@ imap_cleanup_p2( imap_store_t *ctx,
/******************* imap_open_store *******************/
-#ifdef HAVE_LIBSSL
-static int
-do_cram_auth( imap_store_t *ctx, struct imap_cmd *cmdp, const char *prompt )
-{
- imap_server_conf_t *srvc = ((imap_store_conf_t *)ctx->gen.conf)->server;
- char *resp;
- int l;
-
- cmdp->param.cont = 0;
-
- cram( prompt, srvc->user, srvc->pass, &resp, &l );
-
- if (DFlags & VERBOSE) {
- printf( "%s>+> %s\n", ctx->label, resp );
- fflush( stdout );
- }
- if (socket_write( &ctx->conn, resp, l, GiveOwn ) < 0)
- return -1;
- return socket_write( &ctx->conn, "\r\n", 2, KeepOwn );
-}
-#endif
-
static void imap_open_store_connected( int, void * );
#ifdef HAVE_LIBSSL
static void imap_open_store_tlsstarted1( int, void * );
@@ -1536,7 +1543,7 @@ imap_open_store_connected( int ok, void *aux )
if (!ok)
imap_open_store_bail( ctx );
#ifdef HAVE_LIBSSL
- else if (srvc->sconf.use_imaps)
+ else if (srvc->ssl_type == SSL_IMAPS)
socket_start_tls( &ctx->conn, imap_open_store_tlsstarted1 );
#endif
}
@@ -1586,26 +1593,21 @@ imap_open_store_authenticate( imap_store_t *ctx )
if (ctx->greeting != GreetingPreauth) {
#ifdef HAVE_LIBSSL
- if (!srvc->sconf.use_imaps && srvc->use_ssl) {
- /* always try to select SSL support if available */
+ if (srvc->ssl_type == SSL_STARTTLS) {
if (CAP(STARTTLS)) {
imap_exec( ctx, 0,
imap_open_store_authenticate_p2, "STARTTLS" );
return;
} else {
- if (srvc->require_ssl) {
- error( "IMAP error: SSL support not
available\n" );
- imap_open_store_bail( ctx );
- return;
- } else {
- warn( "IMAP warning: SSL support not
available\n" );
- }
+ error( "IMAP error: SSL support not
available\n" );
+ imap_open_store_bail( ctx );
+ return;
}
}
#endif
imap_open_store_authenticate2( ctx );
} else {
#ifdef HAVE_LIBSSL
- if (!srvc->sconf.use_imaps && srvc->require_ssl) {
+ if (srvc->ssl_type == SSL_STARTTLS) {
error( "IMAP error: SSL support not available\n" );
imap_open_store_bail( ctx );
return;
@@ -1646,18 +1648,19 @@ imap_open_store_authenticate_p3( imap_store_t *ctx,
struct imap_cmd *cmd ATTR_UN
}
#endif
-static void
-imap_open_store_authenticate2( imap_store_t *ctx )
+static const char *
+ensure_user( imap_server_conf_t *srvc )
{
- imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
- imap_server_conf_t *srvc = cfg->server;
- char *arg;
-
- info ("Logging in...\n");
if (!srvc->user) {
error( "Skipping account %s, no user\n", srvc->name );
- goto bail;
+ return 0;
}
+ return srvc->user;
+}
+
+static const char *
+ensure_password( imap_server_conf_t *srvc )
+{
if (srvc->pass_cmd) {
FILE *fp;
int ret;
@@ -1666,7 +1669,7 @@ imap_open_store_authenticate2( imap_store_t *ctx )
if (!(fp = popen( srvc->pass_cmd, "r" ))) {
pipeerr:
sys_error( "Skipping account %s, password command
failed", srvc->name );
- goto bail;
+ return 0;
}
if (!fgets( buffer, sizeof(buffer), fp ))
buffer[0] = 0;
@@ -1677,58 +1680,289 @@ imap_open_store_authenticate2( imap_store_t *ctx )
error( "Skipping account %s, password command
crashed\n", srvc->name );
else
error( "Skipping account %s, password command
exited with status %d\n", srvc->name, WEXITSTATUS( ret ) );
- goto bail;
+ return 0;
}
if (!buffer[0]) {
error( "Skipping account %s, password command produced
no output\n", srvc->name );
- goto bail;
+ return 0;
}
buffer[strcspn( buffer, "\n" )] = 0; /* Strip trailing newline
*/
free( srvc->pass ); /* From previous runs */
srvc->pass = nfstrdup( buffer );
} else if (!srvc->pass) {
- char prompt[80];
+ char *pass, prompt[80];
+
sprintf( prompt, "Password (%s): ", srvc->name );
- arg = getpass( prompt );
- if (!arg) {
+ pass = getpass( prompt );
+ if (!pass) {
perror( "getpass" );
exit( 1 );
}
- if (!*arg) {
+ if (!*pass) {
error( "Skipping account %s, no password\n", srvc->name
);
- goto bail;
+ return 0;
}
- /*
- * getpass() returns a pointer to a static buffer. make a copy
- * for long term storage.
- */
- srvc->pass = nfstrdup( arg );
+ /* getpass() returns a pointer to a static buffer. Make a copy
for long term storage. */
+ srvc->pass = nfstrdup( pass );
}
-#ifdef HAVE_LIBSSL
- if (CAP(CRAM)) {
- struct imap_cmd *cmd = new_imap_cmd( sizeof(*cmd) );
+ return srvc->pass;
+}
- info( "Authenticating with CRAM-MD5\n" );
- cmd->param.cont = do_cram_auth;
- imap_exec( ctx, cmd, imap_open_store_authenticate2_p2,
"AUTHENTICATE CRAM-MD5" );
- return;
+#ifdef HAVE_LIBSASL
+
+static sasl_callback_t sasl_callbacks[] = {
+ { SASL_CB_USER, NULL, NULL },
+ { SASL_CB_PASS, NULL, NULL },
+ { SASL_CB_LIST_END, NULL, NULL }
+};
+
+static int
+process_sasl_interact( sasl_interact_t *interact, imap_server_conf_t *srvc )
+{
+ const char *val;
+
+ for (;; ++interact) {
+ switch (interact->id) {
+ case SASL_CB_LIST_END:
+ return 0;
+ case SASL_CB_USER:
+ val = ensure_user( srvc );
+ break;
+ case SASL_CB_PASS:
+ val = ensure_password( srvc );
+ break;
+ default:
+ error( "Error: Unknown SASL interaction ID\n" );
+ return -1;
+ }
+ if (!val)
+ return -1;
+ interact->result = val;
+ interact->len = strlen( val );
+ }
+}
+
+static int
+process_sasl_step( imap_store_t *ctx, int rc, const char *in, unsigned in_len,
+ sasl_interact_t *interact, const char **out, unsigned
*out_len )
+{
+ imap_server_conf_t *srvc = ((imap_store_conf_t *)ctx->gen.conf)->server;
+
+ while (rc == SASL_INTERACT) {
+ if (process_sasl_interact( interact, srvc ) < 0)
+ return -1;
+ rc = sasl_client_step( ctx->sasl, in, in_len, &interact, out,
out_len );
+ }
+ if (rc == SASL_CONTINUE) {
+ ctx->sasl_cont = 1;
+ } else if (rc == SASL_OK) {
+ ctx->sasl_cont = 0;
+ } else {
+ error( "Error: %s\n", sasl_errdetail( ctx->sasl ) );
+ return -1;
+ }
+ return 0;
+}
+
+static int
+decode_sasl_data( const char *prompt, char **in, unsigned *in_len )
+{
+ if (prompt) {
+ int rc;
+ unsigned prompt_len = strlen( prompt );
+ /* We're decoding, the output will be shorter than prompt_len.
*/
+ *in = nfmalloc( prompt_len );
+ rc = sasl_decode64( prompt, prompt_len, *in, prompt_len, in_len
);
+ if (rc != SASL_OK) {
+ free( *in );
+ error( "Error: SASL(%d): %s\n", rc, sasl_errstring( rc,
NULL, NULL ) );
+ return -1;
+ }
+ } else {
+ *in = NULL;
+ *in_len = 0;
+ }
+ return 0;
+}
+
+static int
+encode_sasl_data( const char *out, unsigned out_len, char **enc, unsigned
*enc_len )
+{
+ int rc;
+ unsigned enc_len_max = ((out_len + 2) / 3) * 4 + 1;
+ *enc = nfmalloc( enc_len_max );
+ rc = sasl_encode64( out, out_len, *enc, enc_len_max, enc_len );
+ if (rc != SASL_OK) {
+ free( *enc );
+ error( "Error: SASL(%d): %s\n", rc, sasl_errstring( rc, NULL,
NULL ) );
+ return -1;
}
- if (srvc->require_cram) {
- error( "IMAP error: CRAM-MD5 authentication is not supported by
server\n" );
+ return 0;
+}
+
+static int
+do_sasl_auth( imap_store_t *ctx, struct imap_cmd *cmdp ATTR_UNUSED, const char
*prompt )
+{
+ int rc, ret;
+ unsigned in_len, out_len, enc_len;
+ const char *out;
+ char *in, *enc;
+ sasl_interact_t *interact = NULL;
+
+ if (!ctx->sasl_cont) {
+ error( "Error: IMAP wants more steps despite successful SASL
authentication.\n" );
goto bail;
}
-#endif
- if (CAP(NOLOGIN)) {
- error( "Skipping account %s, server forbids LOGIN\n",
srvc->name );
+ if (decode_sasl_data( prompt, &in, &in_len ) < 0)
goto bail;
+ rc = sasl_client_step( ctx->sasl, in, in_len, &interact, &out, &out_len
);
+ ret = process_sasl_step( ctx, rc, in, in_len, interact, &out, &out_len
);
+ free( in );
+ if (ret < 0)
+ goto bail;
+
+ if (out) {
+ if (encode_sasl_data( out, out_len, &enc, &enc_len ) < 0)
+ goto bail;
+
+ if (DFlags & VERBOSE) {
+ printf( "%s>+> %s\n", ctx->label, enc );
+ fflush( stdout );
+ }
+
+ if (socket_write( &ctx->conn, enc, enc_len, GiveOwn ) < 0)
+ return -1;
+ } else {
+ if (DFlags & VERBOSE) {
+ printf( "%s>+>\n", ctx->label );
+ fflush( stdout );
+ }
+ }
+ return socket_write( &ctx->conn, "\r\n", 2, KeepOwn );
+
+ bail:
+ imap_open_store_bail( ctx );
+ return -1;
+}
+
+static void
+done_sasl_auth( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int
response )
+{
+ if (response == RESP_OK && ctx->sasl_cont) {
+ sasl_interact_t *interact = NULL;
+ const char *out;
+ unsigned out_len;
+ int rc = sasl_client_step( ctx->sasl, NULL, 0, &interact, &out,
&out_len );
+ if (process_sasl_step( ctx, rc, NULL, 0, interact, &out,
&out_len ) < 0)
+ warn( "Warning: SASL reported failure despite
successful IMAP authentication. Ignoring...\n" );
+ else if (out)
+ warn( "Warning: SASL wants more steps despite
successful IMAP authentication. Ignoring...\n" );
+ }
+
+ imap_open_store_authenticate2_p2( ctx, NULL, response );
+}
+
+#endif
+
+static void
+imap_open_store_authenticate2( imap_store_t *ctx )
+{
+ imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
+ imap_server_conf_t *srvc = cfg->server;
+ string_list_t *mech, *cmech;
+ int auth_login = 0;
+#ifdef HAVE_LIBSASL
+ char saslmechs[1024], *saslend = saslmechs;
+#endif
+
+ info( "Logging in...\n" );
+ for (mech = srvc->auth_mechs; mech; mech = mech->next) {
+ int any = !strcmp( mech->string, "*" );
+ for (cmech = ctx->auth_mechs; cmech; cmech = cmech->next) {
+ if (any || !strcasecmp( mech->string, cmech->string )) {
+ if (!strcasecmp( cmech->string, "LOGIN" )) {
+#ifdef HAVE_LIBSSL
+ if (ctx->conn.ssl || !any)
+#endif
+ auth_login = 1;
+ } else {
+#ifdef HAVE_LIBSASL
+ int len = strlen( cmech->string );
+ if (saslend + len + 2 > saslmechs +
sizeof(saslmechs))
+ oob();
+ *saslend++ = ' ';
+ memcpy( saslend, cmech->string, len + 1
);
+ saslend += len;
+#else
+ error( "IMAP error: authentication
mechanism %s is not supported\n", cmech->string );
+ goto bail;
+#endif
+ }
+ }
+ }
+ }
+#ifdef HAVE_LIBSASL
+ if (saslend != saslmechs) {
+ int rc;
+ unsigned out_len = 0;
+ char *enc = NULL;
+ const char *gotmech = NULL, *out = NULL;
+ sasl_interact_t *interact = NULL;
+ struct imap_cmd *cmd;
+ static int sasl_inited;
+
+ if (!sasl_inited) {
+ rc = sasl_client_init( sasl_callbacks );
+ if (rc != SASL_OK) {
+ saslbail:
+ error( "Error: SASL(%d): %s\n", rc,
sasl_errstring( rc, NULL, NULL ) );
+ goto bail;
+ }
+ sasl_inited = 1;
+ }
+
+ rc = sasl_client_new( "imap", srvc->sconf.host, NULL, NULL,
NULL, 0, &ctx->sasl );
+ if (rc != SASL_OK) {
+ if (!ctx->sasl)
+ goto saslbail;
+ error( "Error: %s\n", sasl_errdetail( ctx->sasl ) );
+ goto bail;
+ }
+
+ rc = sasl_client_start( ctx->sasl, saslmechs + 1, &interact,
CAP(SASLIR) ? &out : NULL, &out_len, &gotmech );
+ if (gotmech)
+ info( "Authenticating with SASL mechanism %s...\n",
gotmech );
+ /* Technically, we are supposed to loop over
sasl_client_start(),
+ * but it just calls sasl_client_step() anyway. */
+ if (process_sasl_step( ctx, rc, NULL, 0, interact, CAP(SASLIR)
? &out : NULL, &out_len ) < 0)
+ goto bail;
+ if (out) {
+ if (!out_len)
+ enc = nfstrdup( "=" ); /* A zero-length initial
response is encoded as padding. */
+ else if (encode_sasl_data( out, out_len, &enc, NULL ) <
0)
+ goto bail;
+ }
+
+ cmd = new_imap_cmd( sizeof(*cmd) );
+ cmd->param.cont = do_sasl_auth;
+ imap_exec( ctx, cmd, done_sasl_auth, enc ? "AUTHENTICATE %s %s"
: "AUTHENTICATE %s", gotmech, enc );
+ free( enc );
+ return;
}
+#endif
+ if (auth_login) {
+ if (!ensure_user( srvc ) || !ensure_password( srvc ))
+ goto bail;
+ info( "Logging in...\n" );
#ifdef HAVE_LIBSSL
- if (!ctx->conn.ssl)
+ if (!ctx->conn.ssl)
#endif
- warn( "*** IMAP Warning *** Password is being sent in the
clear\n" );
- imap_exec( ctx, 0, imap_open_store_authenticate2_p2,
- "LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass );
- return;
+ warn( "*** IMAP Warning *** Password is being sent in
the clear\n" );
+ imap_exec( ctx, 0, imap_open_store_authenticate2_p2,
+ "LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass );
+ return;
+ }
+ error( "IMAP error: server supports no acceptable authentication
mechanism\n" );
bail:
imap_open_store_bail( ctx );
@@ -2243,8 +2477,14 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep
)
{
imap_store_conf_t *store;
imap_server_conf_t *server, *srv, sserver;
- const char *type, *name;
+ const char *type, *name, *arg;
int acc_opt = 0;
+#ifdef HAVE_LIBSSL
+ /* Legacy SSL options */
+ int require_ssl = -1, use_imaps = -1;
+ int use_sslv2 = -1, use_sslv3 = -1, use_tlsv1 = -1, use_tlsv11 = -1,
use_tlsv12 = -1;
+ int require_cram = -1;
+#endif
if (!strcasecmp( "IMAPAccount", cfg->cmd )) {
server = nfcalloc( sizeof(*server) );
@@ -2265,32 +2505,31 @@ imap_parse_store( conffile_t *cfg, store_conf_t
**storep )
return 0;
#ifdef HAVE_LIBSSL
- /* this will probably annoy people, but its the best default just in
- * case people forget to turn it on
- */
- server->require_ssl = 1;
- server->sconf.use_tlsv1 = 1;
+ server->ssl_type = -1;
+ server->sconf.ssl_versions = -1;
+ server->sconf.system_certs = 1;
#endif
server->max_in_progress = INT_MAX;
while (getcline( cfg ) && cfg->cmd) {
if (!strcasecmp( "Host", cfg->cmd )) {
/* The imap[s]: syntax is just a backwards compat hack.
*/
+ arg = cfg->val;
#ifdef HAVE_LIBSSL
- if (starts_with( cfg->val, -1, "imaps:", 6 )) {
- cfg->val += 6;
- server->sconf.use_imaps = 1;
- server->sconf.use_sslv2 = 1;
- server->sconf.use_sslv3 = 1;
+ if (starts_with( arg, -1, "imaps:", 6 )) {
+ arg += 6;
+ server->ssl_type = SSL_IMAPS;
+ if (server->sconf.ssl_versions == -1)
+ server->sconf.ssl_versions = SSLv2 |
SSLv3 | TLSv1;
} else
#endif
- {
- if (starts_with( cfg->val, -1, "imap:", 5 ))
- cfg->val += 5;
- }
- if (starts_with( cfg->val, -1, "//", 2 ))
- cfg->val += 2;
- server->sconf.host = nfstrdup( cfg->val );
+ if (starts_with( arg, -1, "imap:", 5 ))
+ arg += 5;
+ if (starts_with( arg, -1, "//", 2 ))
+ arg += 2;
+ if (arg != cfg->val)
+ warn( "%s:%d: Notice: URL notation is
deprecated; use a plain host name and possibly 'SSLType IMAPS' instead\n",
cfg->file, cfg->line );
+ server->sconf.host = nfstrdup( arg );
}
else if (!strcasecmp( "User", cfg->cmd ))
server->user = nfstrdup( cfg->val );
@@ -2314,22 +2553,61 @@ imap_parse_store( conffile_t *cfg, store_conf_t
**storep )
cfg->file, cfg->line,
server->sconf.cert_file );
cfg->err = 1;
}
+ } else if (!strcasecmp( "SystemCertificates", cfg->cmd )) {
+ server->sconf.system_certs = parse_bool( cfg );
+ } else if (!strcasecmp( "SSLType", cfg->cmd )) {
+ if (!strcasecmp( "None", cfg->val )) {
+ server->ssl_type = SSL_None;
+ } else if (!strcasecmp( "STARTTLS", cfg->val )) {
+ server->ssl_type = SSL_STARTTLS;
+ } else if (!strcasecmp( "IMAPS", cfg->val )) {
+ server->ssl_type = SSL_IMAPS;
+ } else {
+ error( "%s:%d: Invalid SSL type\n", cfg->file,
cfg->line );
+ cfg->err = 1;
+ }
+ } else if (!strcasecmp( "SSLVersion", cfg->cmd ) ||
+ !strcasecmp( "SSLVersions", cfg->cmd )) {
+ server->sconf.ssl_versions = 0;
+ arg = cfg->val;
+ do {
+ if (!strcasecmp( "SSLv2", arg )) {
+ server->sconf.ssl_versions |= SSLv2;
+ } else if (!strcasecmp( "SSLv3", arg )) {
+ server->sconf.ssl_versions |= SSLv3;
+ } else if (!strcasecmp( "TLSv1", arg )) {
+ server->sconf.ssl_versions |= TLSv1;
+ } else if (!strcasecmp( "TLSv1.1", arg )) {
+ server->sconf.ssl_versions |= TLSv1_1;
+ } else if (!strcasecmp( "TLSv1.2", arg )) {
+ server->sconf.ssl_versions |= TLSv1_2;
+ } else {
+ error( "%s:%d: Unrecognized SSL
version\n", cfg->file, cfg->line );
+ cfg->err = 1;
+ }
+ } while ((arg = get_arg( cfg, ARG_OPTIONAL, 0 )));
} else if (!strcasecmp( "RequireSSL", cfg->cmd ))
- server->require_ssl = parse_bool( cfg );
+ require_ssl = parse_bool( cfg );
else if (!strcasecmp( "UseIMAPS", cfg->cmd ))
- server->sconf.use_imaps = parse_bool( cfg );
+ use_imaps = parse_bool( cfg );
else if (!strcasecmp( "UseSSLv2", cfg->cmd ))
- server->sconf.use_sslv2 = parse_bool( cfg );
+ use_sslv2 = parse_bool( cfg );
else if (!strcasecmp( "UseSSLv3", cfg->cmd ))
- server->sconf.use_sslv3 = parse_bool( cfg );
+ use_sslv3 = parse_bool( cfg );
else if (!strcasecmp( "UseTLSv1", cfg->cmd ))
- server->sconf.use_tlsv1 = parse_bool( cfg );
+ use_tlsv1 = parse_bool( cfg );
else if (!strcasecmp( "UseTLSv1.1", cfg->cmd ))
- server->sconf.use_tlsv11 = parse_bool( cfg );
+ use_tlsv11 = parse_bool( cfg );
else if (!strcasecmp( "UseTLSv1.2", cfg->cmd ))
- server->sconf.use_tlsv12 = parse_bool( cfg );
- else if (!strcasecmp( "RequireCRAM", cfg->cmd ))
- server->require_cram = parse_bool( cfg );
+ use_tlsv12 = parse_bool( cfg );
+ else if (!strcasecmp( "AuthMech", cfg->cmd ) ||
+ !strcasecmp( "AuthMechs", cfg->cmd )) {
+ arg = cfg->val;
+ do
+ add_string_list( &server->auth_mechs, arg );
+ while ((arg = get_arg( cfg, ARG_OPTIONAL, 0 )));
+ } else if (!strcasecmp( "RequireCRAM", cfg->cmd ))
+ require_cram = parse_bool( cfg );
#endif
else if (!strcasecmp( "Tunnel", cfg->cmd ))
server->sconf.tunnel = nfstrdup( cfg->val );
@@ -2375,15 +2653,61 @@ imap_parse_store( conffile_t *cfg, store_conf_t
**storep )
return 1;
}
#ifdef HAVE_LIBSSL
- server->use_ssl =
- server->sconf.use_sslv2 | server->sconf.use_sslv3 |
- server->sconf.use_tlsv1 | server->sconf.use_tlsv11 |
server->sconf.use_tlsv12;
- if (server->require_ssl && !server->use_ssl) {
- error( "%s '%s' requires SSL but no SSL versions
enabled\n", type, name );
- cfg->err = 1;
- return 1;
+ if ((use_sslv2 & use_sslv3 & use_tlsv1 & use_tlsv11 &
use_tlsv12) != -1 || use_imaps >= 0 || require_ssl >= 0) {
+ if (server->ssl_type >= 0 || server->sconf.ssl_versions
>= 0) {
+ error( "%s '%s': The deprecated UseSSL*,
UseTLS*, UseIMAPS, and RequireSSL options are mutually exlusive with SSLType
and SSLVersions.\n", type, name );
+ cfg->err = 1;
+ return 1;
+ }
+ warn( "Notice: %s '%s': UseSSL*, UseTLS*, UseIMAPS, and
RequireSSL are deprecated. Use SSLType and SSLVersions instead.\n", type, name
);
+ server->sconf.ssl_versions =
+ (use_sslv2 != 1 ? 0 : SSLv2) |
+ (use_sslv3 != 1 ? 0 : SSLv3) |
+ (use_tlsv1 == 0 ? 0 : TLSv1) |
+ (use_tlsv11 != 1 ? 0 : TLSv1_1) |
+ (use_tlsv12 != 1 ? 0 : TLSv1_2);
+ if (use_imaps == 1) {
+ server->ssl_type = SSL_IMAPS;
+ } else if (require_ssl) {
+ server->ssl_type = SSL_STARTTLS;
+ } else if (!server->sconf.ssl_versions) {
+ server->ssl_type = SSL_None;
+ } else {
+ warn( "Notice: %s '%s': 'RequireSSL no' is
being ignored\n", type, name );
+ server->ssl_type = SSL_STARTTLS;
+ }
+ if (server->ssl_type != SSL_None &&
!server->sconf.ssl_versions) {
+ error( "%s '%s' requires SSL but no SSL
versions enabled\n", type, name );
+ cfg->err = 1;
+ return 1;
+ }
+ } else {
+ if (server->sconf.ssl_versions < 0)
+ server->sconf.ssl_versions = TLSv1; /* Most
compatible and still reasonably secure. */
+ if (server->ssl_type < 0)
+ server->ssl_type = server->sconf.tunnel ?
SSL_None : SSL_STARTTLS;
}
#endif
+#ifdef HAVE_LIBSSL
+ if (require_cram >= 0) {
+ if (server->auth_mechs) {
+ error( "%s '%s': The deprecated RequireCRAM
option is mutually exlusive with AuthMech.\n", type, name );
+ cfg->err = 1;
+ return 1;
+ }
+ warn( "Notice: %s '%s': RequireCRAM is deprecated. Use
AuthMech instead.\n", type, name );
+ if (require_cram)
+ add_string_list(&server->auth_mechs,
"CRAM-MD5");
+ }
+#endif
+ if (!server->auth_mechs)
+ add_string_list( &server->auth_mechs, "*" );
+ if (!server->sconf.port)
+ server->sconf.port =
+#ifdef HAVE_LIBSSL
+ server->ssl_type == SSL_IMAPS ? 993 :
+#endif
+ 143;
}
if (store) {
if (!store->server) {
diff --git a/src/drv_maildir.c b/src/drv_maildir.c
index f151b5b..fc73f7b 100644
--- a/src/drv_maildir.c
+++ b/src/drv_maildir.c
@@ -57,6 +57,8 @@ typedef struct maildir_store_conf {
#ifdef USE_DB
int alt_map;
#endif /* USE_DB */
+ char info_delimiter;
+ char *info_prefix, *info_stop; /* precalculated from info_delimiter */
} maildir_store_conf_t;
typedef struct maildir_message {
@@ -84,14 +86,14 @@ static int MaildirCount;
static const char Flags[] = { 'D', 'F', 'R', 'S', 'T' };
static unsigned char
-maildir_parse_flags( const char *base )
+maildir_parse_flags( const char *info_prefix, const char *base )
{
const char *s;
unsigned i;
unsigned char flags;
flags = 0;
- if ((s = strstr( base, ":2," )))
+ if ((s = strstr( base, info_prefix )))
for (s += 3, i = 0; i < as(Flags); i++)
if (strchr( s, Flags[i] ))
flags |= (1 << i);
@@ -413,9 +415,9 @@ maildir_validate( const char *box, int create,
maildir_store_t *ctx )
#ifdef USE_DB
static void
-make_key( DBT *tkey, char *name )
+make_key( const char *info_stop, DBT *tkey, char *name )
{
- char *u = strpbrk( name, ":," );
+ char *u = strpbrk( name, info_stop );
tkey->data = name;
tkey->size = u ? (size_t)(u - name) : strlen( name );
}
@@ -439,7 +441,7 @@ maildir_set_uid( maildir_store_t *ctx, const char *name,
int *uid )
return DRV_BOX_BAD;
}
if (uid) {
- make_key( &key, (char *)name );
+ make_key( ((maildir_store_conf_t *)ctx->gen.conf)->info_stop,
&key, (char *)name );
value.data = uid;
value.size = sizeof(*uid);
if ((ret = ctx->db->put( ctx->db, 0, &key, &value, 0 )))
@@ -615,6 +617,7 @@ maildir_compare( const void *l, const void *r )
static int
maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
{
+ maildir_store_conf_t *conf = (maildir_store_conf_t *)ctx->gen.conf;
DIR *d;
FILE *f;
struct dirent *e;
@@ -694,7 +697,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
ctx->gen.recent += i;
#ifdef USE_DB
if (ctx->db) {
- make_key( &key, e->d_name );
+ make_key( conf->info_stop, &key,
e->d_name );
if ((ret = ctx->db->get( ctx->db, 0,
&key, &value, 0 ))) {
if (ret != DB_NOTFOUND) {
ctx->db->err( ctx->db,
ret, "Maildir error: db->get()" );
@@ -834,7 +837,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
if ((u = strstr( entry->base, ",U=" )))
for (ru = u + 3; isdigit( (unsigned
char)*ru ); ru++);
else
- u = ru = strchr( entry->base, ':' );
+ u = ru = strchr( entry->base,
conf->info_delimiter );
fnl = (u ?
nfsnprintf( buf + bl, sizeof(buf) - bl,
"%s/%.*s,U=%d%s", subdirs[entry->recent], (int)(u - entry->base), entry->base,
uid, ru ) :
nfsnprintf( buf + bl, sizeof(buf) - bl,
"%s/%s,U=%d", subdirs[entry->recent], entry->base, uid ))
@@ -906,7 +909,7 @@ maildir_init_msg( maildir_store_t *ctx, maildir_message_t
*msg, msg_t *entry )
msg->gen.status |= M_RECENT;
if (ctx->gen.opts & OPEN_FLAGS) {
msg->gen.status |= M_FLAGS;
- msg->gen.flags = maildir_parse_flags( msg->base );
+ msg->gen.flags = maildir_parse_flags( ((maildir_store_conf_t
*)ctx->gen.conf)->info_prefix, msg->base );
} else
msg->gen.flags = 0;
}
@@ -1177,16 +1180,16 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg,
msg_data_t *data,
}
close( fd );
if (!(gmsg->status & M_FLAGS))
- data->flags = maildir_parse_flags( msg->base );
+ data->flags = maildir_parse_flags( ((maildir_store_conf_t
*)gctx->conf)->info_prefix, msg->base );
cb( DRV_OK, aux );
}
static int
-maildir_make_flags( int flags, char *buf )
+maildir_make_flags( char info_delimiter, int flags, char *buf )
{
unsigned i, d;
- buf[0] = ':';
+ buf[0] = info_delimiter;
buf[1] = '2';
buf[2] = ',';
for (d = 3, i = 0; i < as(Flags); i++)
@@ -1231,7 +1234,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int
to_trash,
box = ctx->trash;
}
- maildir_make_flags( data->flags, fbuf );
+ maildir_make_flags( ((maildir_store_conf_t
*)gctx->conf)->info_delimiter, data->flags, fbuf );
nfsnprintf( buf, sizeof(buf), "%s/tmp/%s%s", box, base, fbuf );
if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) {
if (errno != ENOENT || !to_trash) {
@@ -1302,6 +1305,7 @@ static void
maildir_set_flags( store_t *gctx, message_t *gmsg, int uid ATTR_UNUSED, int
add, int del,
void (*cb)( int sts, void *aux ), void *aux )
{
+ maildir_store_conf_t *conf = (maildir_store_conf_t *)gctx->conf;
maildir_store_t *ctx = (maildir_store_t *)gctx;
maildir_message_t *msg = (maildir_message_t *)gmsg;
char *s, *p;
@@ -1319,7 +1323,7 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int
uid ATTR_UNUSED, int add,
oob();
memcpy( buf + bl, msg->base, ol + 1 );
memcpy( nbuf + bl, msg->base, ol + 1 );
- if ((s = strstr( nbuf + bl, ":2," ))) {
+ if ((s = strstr( nbuf + bl, conf->info_prefix ))) {
s += 3;
fl = ol - (s - (nbuf + bl));
for (i = 0; i < as(Flags); i++) {
@@ -1337,7 +1341,7 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int
uid ATTR_UNUSED, int add,
}
tl = ol + 3 + fl;
} else {
- tl = ol + maildir_make_flags( msg->gen.flags, nbuf + bl
+ ol );
+ tl = ol + maildir_make_flags( conf->info_delimiter,
msg->gen.flags, nbuf + bl + ol );
}
if (!rename( buf, nbuf ))
break;
@@ -1362,7 +1366,7 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name
)
{
int ret;
- make_key( &key, (char *)name );
+ make_key( ((maildir_store_conf_t *)ctx->gen.conf)->info_stop, &key,
(char *)name );
if ((ret = ctx->db->del( ctx->db, 0, &key, 0 ))) {
ctx->db->err( ctx->db, ret, "Maildir error: db->del()" );
return DRV_BOX_BAD;
@@ -1384,7 +1388,7 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg,
for (;;) {
nfsnprintf( buf, sizeof(buf), "%s/%s/%s", gctx->path,
subdirs[gmsg->status & M_RECENT], msg->base );
- s = strstr( msg->base, ":2," );
+ s = strstr( msg->base, ((maildir_store_conf_t
*)gctx->conf)->info_prefix );
nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%ld.%d_%d.%s%s",
ctx->trash,
subdirs[gmsg->status & M_RECENT], (long)time( 0 ),
Pid, ++MaildirCount, Hostname, s ? s : "" );
if (!rename( buf, nbuf ))
@@ -1484,6 +1488,7 @@ maildir_parse_store( conffile_t *cfg, store_conf_t
**storep )
if (strcasecmp( "MaildirStore", cfg->cmd ))
return 0;
store = nfcalloc( sizeof(*store) );
+ store->info_delimiter = FieldDelimiter;
store->gen.driver = &maildir_driver;
store->gen.name = nfstrdup( cfg->val );
@@ -1496,10 +1501,24 @@ maildir_parse_store( conffile_t *cfg, store_conf_t
**storep )
else if (!strcasecmp( "AltMap", cfg->cmd ))
store->alt_map = parse_bool( cfg );
#endif /* USE_DB */
- else
+ else if (!strcasecmp( "InfoDelimiter", cfg->cmd )) {
+ if (strlen( cfg->val ) != 1) {
+ error( "%s:%d: Info delimiter must be exactly
one character long\n", cfg->file, cfg->line );
+ cfg->err = 1;
+ continue;
+ }
+ store->info_delimiter = cfg->val[0];
+ if (!ispunct( store->info_delimiter )) {
+ error( "%s:%d: Info delimiter must be a
punctuation character\n", cfg->file, cfg->line );
+ cfg->err = 1;
+ continue;
+ }
+ } else
parse_generic_store( &store->gen, cfg );
if (!store->inbox)
store->inbox = expand_strdup( "~/Maildir" );
+ nfasprintf( &store->info_prefix, "%c2,", store->info_delimiter );
+ nfasprintf( &store->info_stop, "%c,", store->info_delimiter );
*storep = &store->gen;
return 1;
}
diff --git a/src/main.c b/src/main.c
index 770de0d..0ff9ec8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -33,6 +33,11 @@
int DFlags;
int UseFSync = 1;
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|| defined(__CYGWIN__)
+char FieldDelimiter = ';';
+#else
+char FieldDelimiter = ':';
+#endif
int Pid; /* for maildir and imap */
char Hostname[256]; /* for maildir */
diff --git a/src/mbsync.1 b/src/mbsync.1
index 2af9178..2f7e7ed 100644
--- a/src/mbsync.1
+++ b/src/mbsync.1
@@ -229,6 +229,13 @@ The location of the \fBINBOX\fR. This is \fInot\fR
relative to \fBPath\fR,
but it is allowed to place the \fBINBOX\fR inside the \fBPath\fR.
(Default: \fI~/Maildir\fR)
..
+.TP
+\fBInfoDelimiter\fR \fIdelim\fR
+The character used to delimit the info field from a message's basename.
+The Maildir standard defines this to be the colon, but this is incompatible
+with DOS/Windows file systems.
+(Default: the value of \fBFieldDelimiter\fR)
+..
.SS IMAP4 Accounts
.TP
\fBIMAPAccount\fR \fIname\fR
@@ -238,8 +245,9 @@ Define the IMAP4 Account \fIname\fR, opening a section for
its parameters.
\fBHost\fR \fIhost\fR
Specify the DNS name or IP address of the IMAP server.
.br
-If \fBTunnel\fR is used, this setting is used only for SSL host certificate
-verification, if provided.
+If \fBTunnel\fR is used, this setting is needed only if \fBSSLType\fR is
+not \fINone\fR and \fBCertificateFile\fR is not used,
+in which case the host name is used for certificate subject verification.
..
.TP
\fBPort\fR \fIport\fR
@@ -271,66 +279,54 @@ optional.
Specify a command to run to establish a connection rather than opening a TCP
socket. This allows you to run an IMAP session over an SSH tunnel, for
example.
-.br
-If \fBUseIMAPS\fR is disabled and the tunnel opens a preauthenticated
-connection, \fBRequireSSL\fR also needs to be disabled.
-If the connection is not preauthenticated, but the tunnel is secure,
-disabling \fBRequireSSL\fR and \fBUseTLSv1\fR is recommended.
..
.TP
-\fBRequireCRAM\fR \fIyes\fR|\fIno\fR
-If set to \fIyes\fR, \fBmbsync\fR will abort the connection if no CRAM-MD5
-authentication is possible. (Default: \fIno\fR)
+\fBAuthMechs\fR \fItype\fR ...
+The list of acceptable authentication mechanisms.
+In addition to the mechanisms listed in the SASL registry (link below),
+the legacy IMAP \fBLOGIN\fR mechanism is known.
+The wildcard \fB*\fR represents all mechanisms that are deemed secure
+enough for the current \fBSSLType\fR setting.
+The actually used mechanism is the most secure choice from the intersection
+of this list, the list supplied by the server, and the installed SASL modules.
+(Default: \fB*\fR)
..
.TP
-\fBUseIMAPS\fR \fIyes\fR|\fIno\fR
-If set to \fIyes\fR, the default for \fBPort\fR is changed to 993 and
-\fBmbsync\fR will start SSL negotiation immediately after establishing
-the connection to the server.
+\fBSSLType\fR {\fINone\fR|\fISTARTTLS\fR|\fIIMAPS\fR}
+Select the connection security/encryption method:
.br
-Note that modern servers support SSL on the regular IMAP port 143 via the
-STARTTLS extension, which will be used automatically by default.
-..
-.TP
-\fBRequireSSL\fR \fIyes\fR|\fIno\fR
-\fBmbsync\fR will abort the connection if a TLS/SSL session cannot be
-established with the IMAP server. (Default: \fIyes\fR)
-..
-.TP
-\fBCertificateFile\fR \fIpath\fR
-File containing additional X.509 certificates used to verify server
-identities. Directly matched peer certificates are always trusted,
-regardless of validity.
+\fINone\fR - no security.
+This is the default when \fBTunnel\fR is set, as tunnels are usually secure.
.br
-Note that the system's default certificate store is always used and should
-not be specified here.
-..
-.TP
-\fBUseSSLv2\fR \fIyes\fR|\fIno\fR
-Use SSLv2 for communication with the IMAP server over SSL?
+\fISTARTTLS\fR - security is established via the STARTTLS extension
+after connecting the regular IMAP port 143. Most servers support this,
+so it is the default (unless a tunnel is used).
.br
-Note that this option is deprecated for security reasons.
-(Default: \fIno\fR)
+\fIIMAPS\fR - security is established by starting SSL/TLS negotiation
+right after connecting the secure IMAP port 993.
..
.TP
-\fBUseSSLv3\fR \fIyes\fR|\fIno\fR
-Use SSLv3 for communication with the IMAP server over SSL?
-(Default: \fIno\fR)
+\fBSSLVersions\fR [\fISSLv2\fR] [\fISSLv3\fR] [\fITLSv1\fR] [\fITLSv1.1\fR]
[\fITLSv1.2\fR]
+Select the acceptable SSL/TLS versions.
+Use of SSLv2 is strongly discouraged for security reasons, but might be the
+only option on some very old servers.
+Generally, the newest TLS version is recommended, but as this confuses some
+servers, \fBTLSv1\fR is the default.
..
.TP
-\fBUseTLSv1\fR \fIyes\fR|\fIno\fR
-Use TLSv1 for communication with the IMAP server over SSL?
+\fBSystemCertificates\fR \fIyes\fR|\fIno\fR
+Whether the system's default root cerificate store should be loaded.
(Default: \fIyes\fR)
..
.TP
-\fBUseTLSv1.1\fR \fIyes\fR|\fIno\fR
-Use TLSv1.1 for communication with the IMAP server over SSL?
-(Default: \fIno\fR)
-..
-.TP
-\fBUseTLSv1.2\fR \fIyes\fR|\fIno\fR
-Use TLSv1.2 for communication with the IMAP server over SSL?
-(Default: \fIno\fR)
+\fBCertificateFile\fR \fIpath\fR
+File containing additional X.509 certificates used to verify server
+identities. Directly matched peer certificates are always trusted,
+regardless of validity.
+.br
+Note that the system's default certificate store is always used
+(unless \fBSystemCertificates\fR is disabled)
+and should not be specified here.
..
.TP
\fBPipelineDepth\fR \fIdepth\fR
@@ -524,7 +520,8 @@ mailbox name to make up a complete path.
.br
This option can be used outside any section for a global effect. In this case
the appended string is made up according to the pattern
-\fB:\fImaster\fB:\fImaster-box\fB_:\fIslave\fB:\fIslave-box\fR.
+\fB:\fImaster\fB:\fImaster-box\fB_:\fIslave\fB:\fIslave-box\fR
+(see also \fBFieldDelimiter\fR below).
.br
(Global default: \fI~/.mbsync/\fR).
..
@@ -560,6 +557,16 @@ in particular modern systems like ext4, btrfs and xfs. The
performance impact
on older file systems may be disproportionate.
(Default: \fIyes\fR)
..
+.TP
+\fBFieldDelimiter\fR \fIdelim\fR
+The character to use to delimit fields in the string appended to a global
+\fBSyncState\fR.
+\fBmbsync\fR prefers to use the colon, but this is incompatible with
+DOS/Windows file systems.
+This option is meaningless for \fBSyncState\fR if the latter is \fB*\fR,
+obviously. However, it also determines the default of \fBInfoDelimiter\fR.
+(Global default: \fI;\fR on Windows, \fI:\fR everywhere else)
+..
.SH RECOMMENDATIONS
Make sure your IMAP server does not auto-expunge deleted messages - it is
slow, and semantically somewhat questionable. Specifically, Gmail needs to
@@ -611,6 +618,9 @@ Directory containing synchronization state files
mdconvert(1), isync(1), mutt(1), maildir(5)
.P
Up to date information on \fBmbsync\fR can be found at http://isync.sf.net/
+.P
+SASL mechanisms are listed at
+http://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml
..
.SH AUTHORS
Originally written by Michael R. Elkins,
diff --git a/src/socket.c b/src/socket.c
index fc06f8b..0108243 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -58,8 +58,6 @@ socket_fail( conn_t *conn )
}
#ifdef HAVE_LIBSSL
-static int ssl_data_idx;
-
static int
ssl_return( const char *func, conn_t *conn, int ret )
{
@@ -156,10 +154,10 @@ verify_hostname( X509 *cert, const char *hostname )
static int
verify_cert_host( const server_conf_t *conf, conn_t *sock )
{
+ int i;
+ long err;
X509 *cert;
-
- if (!conf->host || sock->force_trusted > 0)
- return 0;
+ STACK_OF(X509_OBJECT) *trusted;
cert = SSL_get_peer_certificate( sock->ssl );
if (!cert) {
@@ -167,31 +165,24 @@ verify_cert_host( const server_conf_t *conf, conn_t *sock
)
return -1;
}
- return verify_hostname( cert, conf->host );
-}
+ trusted = (STACK_OF(X509_OBJECT) *)sock->conf->trusted_certs;
+ for (i = 0; i < sk_X509_OBJECT_num( trusted ); i++) {
+ if (!X509_cmp( cert, sk_X509_OBJECT_value( trusted, i
)->data.x509 ))
+ return 0;
+ }
-static int
-ssl_verify_callback( int ok, X509_STORE_CTX *ctx )
-{
- SSL *ssl = X509_STORE_CTX_get_ex_data( ctx,
SSL_get_ex_data_X509_STORE_CTX_idx() );
- conn_t *conn = SSL_get_ex_data( ssl, ssl_data_idx );
-
- if (!conn->force_trusted) {
- X509 *cert = sk_X509_value( ctx->chain, 0 );
- STACK_OF(X509_OBJECT) *trusted = (STACK_OF(X509_OBJECT)
*)conn->conf->trusted_certs;
- int i;
-
- conn->force_trusted = -1;
- for (i = 0; i < sk_X509_OBJECT_num( trusted ); i++) {
- if (!X509_cmp( cert, sk_X509_OBJECT_value( trusted, i
)->data.x509 )) {
- conn->force_trusted = 1;
- break;
- }
- }
+ err = SSL_get_verify_result( sock->ssl );
+ if (err != X509_V_OK) {
+ error( "SSL error connecting %s: %s\n", sock->name,
ERR_error_string( err, NULL ) );
+ return -1;
}
- if (conn->force_trusted > 0)
- ok = 1;
- return ok;
+
+ if (!conf->host) {
+ error( "SSL error connecting %s: Neither host nor matching
certificate specified\n", sock->name );
+ return -1;
+ }
+
+ return verify_hostname( cert, conf->host );
}
static int
@@ -205,18 +196,18 @@ init_ssl_ctx( const server_conf_t *conf )
mconf->SSLContext = SSL_CTX_new( SSLv23_client_method() );
- if (!conf->use_sslv2)
+ if (!(conf->ssl_versions & SSLv2))
options |= SSL_OP_NO_SSLv2;
- if (!conf->use_sslv3)
+ if (!(conf->ssl_versions & SSLv3))
options |= SSL_OP_NO_SSLv3;
- if (!conf->use_tlsv1)
+ if (!(conf->ssl_versions & TLSv1))
options |= SSL_OP_NO_TLSv1;
#ifdef SSL_OP_NO_TLSv1_1
- if (!conf->use_tlsv11)
+ if (!(conf->ssl_versions & TLSv1_1))
options |= SSL_OP_NO_TLSv1_1;
#endif
#ifdef SSL_OP_NO_TLSv1_2
- if (!conf->use_tlsv12)
+ if (!(conf->ssl_versions & TLSv1_2))
options |= SSL_OP_NO_TLSv1_2;
#endif
@@ -228,11 +219,11 @@ init_ssl_ctx( const server_conf_t *conf )
return 0;
}
mconf->trusted_certs = (_STACK *)sk_X509_OBJECT_dup(
SSL_CTX_get_cert_store( mconf->SSLContext )->objs );
- if (!SSL_CTX_set_default_verify_paths( mconf->SSLContext ))
+ if (mconf->system_certs && !SSL_CTX_set_default_verify_paths(
mconf->SSLContext ))
warn( "Warning: Unable to load default certificate files: %s\n",
ERR_error_string( ERR_get_error(), 0 ) );
- SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_PEER,
ssl_verify_callback );
+ SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_NONE, NULL );
mconf->ssl_ctx_valid = 1;
return 1;
@@ -251,7 +242,6 @@ socket_start_tls( conn_t *conn, void (*cb)( int ok, void
*aux ) )
if (!ssl_inited) {
SSL_library_init();
SSL_load_error_strings();
- ssl_data_idx = SSL_get_ex_new_index( 0, NULL, NULL, NULL, NULL
);
ssl_inited = 1;
}
@@ -263,7 +253,6 @@ socket_start_tls( conn_t *conn, void (*cb)( int ok, void
*aux ) )
conn->ssl = SSL_new( ((server_conf_t *)conn->conf)->SSLContext );
SSL_set_fd( conn->ssl, conn->fd );
SSL_set_mode( conn->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER );
- SSL_set_ex_data( conn->ssl, ssl_data_idx, conn );
conn->state = SCK_STARTTLS;
start_tls_p2( conn );
}
@@ -272,7 +261,6 @@ static void
start_tls_p2( conn_t *conn )
{
if (ssl_return( "connect to", conn, SSL_connect( conn->ssl ) ) > 0) {
- /* verify whether the server hostname matches the certificate */
if (verify_cert_host( conn->conf, conn )) {
start_tls_p3( conn, 0 );
} else {
@@ -312,7 +300,7 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux
) )
sock->callbacks.connect = cb;
- /* open connection to IMAP server */
+ /* open connection to server */
if (conf->tunnel) {
int a[2];
@@ -352,7 +340,7 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux
) )
hints.ai_flags = AI_ADDRCONFIG;
infon( "Resolving %s... ", conf->host );
if ((gaierr = getaddrinfo( conf->host, NULL, &hints,
&sock->addrs ))) {
- error( "IMAP error: Cannot resolve server '%s': %s\n",
conf->host, gai_strerror( gaierr ) );
+ error( "Error: Cannot resolve server '%s': %s\n",
conf->host, gai_strerror( gaierr ) );
socket_connect_bail( sock );
return;
}
@@ -365,7 +353,7 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux
) )
infon( "Resolving %s... ", conf->host );
he = gethostbyname( conf->host );
if (!he) {
- error( "IMAP error: Cannot resolve server '%s': %s\n",
conf->host, hstrerror( h_errno ) );
+ error( "Error: Cannot resolve server '%s': %s\n",
conf->host, hstrerror( h_errno ) );
socket_connect_bail( sock );
return;
}
@@ -381,7 +369,6 @@ static void
socket_connect_one( conn_t *sock )
{
int s;
- ushort port;
#ifdef HAVE_IPV6
struct addrinfo *ai;
#else
@@ -400,18 +387,13 @@ socket_connect_one( conn_t *sock )
return;
}
- port = sock->conf->port ? sock->conf->port :
-#ifdef HAVE_LIBSSL
- sock->conf->use_imaps ? 993 :
-#endif
- 143;
#ifdef HAVE_IPV6
if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *in6 = ((struct sockaddr_in6 *)ai->ai_addr);
char sockname[64];
- in6->sin6_port = htons( port );
+ in6->sin6_port = htons( sock->conf->port );
nfasprintf( &sock->name, "%s ([%s]:%hu)",
- sock->conf->host, inet_ntop( AF_INET6,
&in6->sin6_addr, sockname, sizeof(sockname) ), port );
+ sock->conf->host, inet_ntop( AF_INET6,
&in6->sin6_addr, sockname, sizeof(sockname) ), sock->conf->port );
} else
#endif
{
@@ -421,9 +403,9 @@ socket_connect_one( conn_t *sock )
in->sin_family = AF_INET;
in->sin_addr.s_addr = *((int *)*sock->curr_addr);
#endif
- in->sin_port = htons( port );
+ in->sin_port = htons( sock->conf->port );
nfasprintf( &sock->name, "%s (%s:%hu)",
- sock->conf->host, inet_ntoa( in->sin_addr ), port );
+ sock->conf->host, inet_ntoa( in->sin_addr ),
sock->conf->port );
}
#ifdef HAVE_IPV6
@@ -735,58 +717,3 @@ socket_fd_cb( int events, void *aux )
if (events & POLLIN)
socket_fill( conn );
}
-
-#ifdef HAVE_LIBSSL
-/* this isn't strictly socket code, but let's have all OpenSSL use in one
file. */
-
-#define ENCODED_SIZE(n) (4*((n+2)/3))
-
-static char
-hexchar( unsigned int b )
-{
- if (b < 10)
- return '0' + b;
- return 'a' + (b - 10);
-}
-
-void
-cram( const char *challenge, const char *user, const char *pass, char
**_final, int *_finallen )
-{
- char *response, *final;
- unsigned hashlen;
- int i, clen, blen, flen, olen;
- unsigned char hash[16];
- char buf[256], hex[33];
- HMAC_CTX hmac;
-
- HMAC_Init( &hmac, (unsigned char *)pass, strlen( pass ), EVP_md5() );
-
- clen = strlen( challenge );
- /* response will always be smaller than challenge because we are
decoding. */
- response = nfcalloc( 1 + clen );
- EVP_DecodeBlock( (unsigned char *)response, (unsigned char *)challenge,
clen );
- HMAC_Update( &hmac, (unsigned char *)response, strlen( response ) );
- free( response );
-
- hashlen = sizeof(hash);
- HMAC_Final( &hmac, hash, &hashlen );
- assert( hashlen == sizeof(hash) );
-
- hex[32] = 0;
- for (i = 0; i < 16; i++) {
- hex[2 * i] = hexchar( (hash[i] >> 4) & 0xf );
- hex[2 * i + 1] = hexchar( hash[i] & 0xf );
- }
-
- blen = nfsnprintf( buf, sizeof(buf), "%s %s", user, hex );
-
- flen = ENCODED_SIZE( blen );
- final = nfmalloc( flen + 1 );
- final[flen] = 0;
- olen = EVP_EncodeBlock( (unsigned char *)final, (unsigned char *)buf,
blen );
- assert( olen == flen );
-
- *_final = final;
- *_finallen = flen;
-}
-#endif
diff --git a/src/socket.h b/src/socket.h
index 193330e..e09a9e1 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -25,18 +25,28 @@
#include "common.h"
+#ifdef HAVE_LIBSSL
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
typedef struct stack_st _STACK;
+enum {
+ SSLv2 = 1,
+ SSLv3 = 2,
+ TLSv1 = 4,
+ TLSv1_1 = 8,
+ TLSv1_2 = 16
+};
+#endif
+
typedef struct server_conf {
char *tunnel;
char *host;
int port;
#ifdef HAVE_LIBSSL
char *cert_file;
- char use_imaps;
- char use_sslv2, use_sslv3, use_tlsv1, use_tlsv11, use_tlsv12;
+ char system_certs;
+ char ssl_versions;
/* these are actually variables and are leaked at the end */
char ssl_ctx_valid;
@@ -65,7 +75,6 @@ typedef struct {
char *name;
#ifdef HAVE_LIBSSL
SSL *ssl;
- int force_trusted;
#endif
void (*bad_callback)( void *aux ); /* async fail while sending or
listening */
@@ -113,7 +122,4 @@ char *socket_read_line( conn_t *sock ); /* don't free
return value; never waits
typedef enum { KeepOwn = 0, GiveOwn } ownership_t;
int socket_write( conn_t *sock, char *buf, int len, ownership_t takeOwn );
-void cram( const char *challenge, const char *user, const char *pass,
- char **_final, int *_finallen );
-
#endif
diff --git a/src/sync.c b/src/sync.c
index 443da1b..e222f6f 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -153,6 +153,7 @@ typedef struct {
channel_conf_t *chan;
store_t *ctx[2];
driver_t *drv[2];
+ const char *orig_name[2];
int state[2], ref_count, nsrecs, ret, lfd;
int new_total[2], new_done[2];
int flags_total[2], flags_done[2];
@@ -600,13 +601,13 @@ sync_boxes( store_t *ctx[], const char *names[],
channel_conf_t *chan,
svars->srecadd = &svars->srecs;
for (t = 0; t < 2; t++) {
- ctx[t]->orig_name =
+ svars->orig_name[t] =
(!names[t] || (ctx[t]->conf->map_inbox && !strcmp(
ctx[t]->conf->map_inbox, names[t] ))) ?
"INBOX" : names[t];
if (!ctx[t]->conf->flat_delim) {
- svars->box_name[t] = nfstrdup( ctx[t]->orig_name );
- } else if (map_name( ctx[t]->orig_name, &svars->box_name[t], 0,
"/", ctx[t]->conf->flat_delim ) < 0) {
- error( "Error: canonical mailbox name '%s' contains
flattened hierarchy delimiter\n", ctx[t]->orig_name );
+ svars->box_name[t] = nfstrdup( svars->orig_name[t] );
+ } else if (map_name( svars->orig_name[t], &svars->box_name[t],
0, "/", ctx[t]->conf->flat_delim ) < 0) {
+ error( "Error: canonical mailbox name '%s' contains
flattened hierarchy delimiter\n", svars->orig_name[t] );
svars->ret = SYNC_FAIL;
sync_bail3( svars );
return;
@@ -619,7 +620,7 @@ sync_boxes( store_t *ctx[], const char *names[],
channel_conf_t *chan,
* don't run into uninitialized variables. */
sync_ref( svars );
for (t = 0; t < 2; t++) {
- info( "Selecting %s %s...\n", str_ms[t], ctx[t]->orig_name );
+ info( "Selecting %s %s...\n", str_ms[t], svars->orig_name[t] );
svars->drv[t]->select( ctx[t], svars->box_name[t],
(chan->ops[t] & OP_CREATE) != 0, box_selected, AUX );
if (check_cancel( svars ))
break;
@@ -669,9 +670,10 @@ box_selected( int sts, void *aux )
if (chan->sync_state)
nfasprintf( &svars->dname, "%s%s", chan->sync_state,
csname );
else {
+ char c = FieldDelimiter;
cmname = clean_strdup( svars->box_name[M] );
- nfasprintf( &svars->dname, "%s:%s:%s_:%s:%s",
global_conf.sync_state,
- chan->stores[M]->name, cmname,
chan->stores[S]->name, csname );
+ nfasprintf( &svars->dname, "%s%c%s%c%s_%c%s%c%s",
global_conf.sync_state,
+ c, chan->stores[M]->name, c, cmname, c,
chan->stores[S]->name, c, csname );
free( cmname );
}
free( csname );
@@ -704,7 +706,7 @@ box_selected( int sts, void *aux )
}
if (fcntl( svars->lfd, F_SETLK, &lck )) {
error( "Error: channel :%s:%s-:%s:%s is locked\n",
- chan->stores[M]->name, ctx[M]->orig_name,
chan->stores[S]->name, ctx[S]->orig_name );
+ chan->stores[M]->name, svars->orig_name[M],
chan->stores[S]->name, svars->orig_name[S] );
svars->ret = SYNC_FAIL;
sync_bail1( svars );
return;
@@ -1404,7 +1406,7 @@ box_loaded( int sts, void *aux )
if (svars->chan->expire_unread < 0 && (unsigned)alive * 2 >
svars->chan->max_messages) {
error( "%s: %d unread messages in excess of MaxMessages
(%d).\n"
"Please set ExpireUnread to decide outcome.
Skipping mailbox.\n",
- svars->ctx[S]->orig_name, alive,
svars->chan->max_messages );
+ svars->orig_name[S], alive,
svars->chan->max_messages );
svars->ret |= SYNC_FAIL;
cancel_sync( svars );
return;
------------------------------------------------------------------------------
New Year. New Location. New Benefits. New Data Center in Ashburn, VA.
GigeNET is offering a free month of service with a new server in Ashburn.
Choose from 2 high performing configs, both with 100TB of bandwidth.
Higher redundancy.Lower latency.Increased capacity.Completely compliant.
http://p.sf.net/sfu/gigenet
_______________________________________________
isync-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel