Merge branch '1.3'

This commit is contained in:
Oswald Buddenhagen 2019-10-03 20:17:54 +02:00
commit 462fed556a
6 changed files with 114 additions and 48 deletions

View File

@ -18,14 +18,14 @@ fi
need_perl=5.14 need_perl=5.14
AC_CACHE_CHECK([whether perl is recent enough], ob_cv_perl_ver, [ AC_CACHE_CHECK([whether perl is recent enough], ob_cv_perl_ver, [
if $PERL -e "use v$need_perl;"; then if $PERL -e "use v$need_perl;" 2> /dev/null; then
ob_cv_perl_ver=yes ob_cv_perl_ver=yes
else else
ob_cv_perl_ver=no ob_cv_perl_ver=no
fi fi
]) ])
if test "x$ob_cv_perl_ver" = "xno"; then if test "x$ob_cv_perl_ver" = "xno"; then
AC_MSG_ERROR([perl is too old]) AC_MSG_ERROR([perl is too old, need v$need_perl])
fi fi
AC_CACHE_CHECK([whether strftime supports %z], ob_cv_strftime_z, AC_CACHE_CHECK([whether strftime supports %z], ob_cv_strftime_z,
@ -94,7 +94,7 @@ if test "x$ob_cv_with_ssl" != xno; then
sav_LDFLAGS=$LDFLAGS sav_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $SSL_LDFLAGS" LDFLAGS="$LDFLAGS $SSL_LDFLAGS"
AC_CHECK_LIB(dl, dlopen, [LIBDL=-ldl]) AC_CHECK_LIB(dl, dlopen, [LIBDL=-ldl])
AC_CHECK_LIB(crypto, CRYPTO_lock, [LIBCRYPTO=-lcrypto]) AC_CHECK_LIB(crypto, X509_cmp, [LIBCRYPTO=-lcrypto])
AC_CHECK_LIB(ssl, SSL_connect, AC_CHECK_LIB(ssl, SSL_connect,
[SSL_LIBS="-lssl $LIBCRYPTO $LIBDL" have_ssl_paths=yes]) [SSL_LIBS="-lssl $LIBCRYPTO $LIBDL" have_ssl_paths=yes])
LDFLAGS=$sav_LDFLAGS LDFLAGS=$sav_LDFLAGS

View File

@ -33,6 +33,7 @@
typedef unsigned char uchar; typedef unsigned char uchar;
typedef unsigned short ushort; typedef unsigned short ushort;
typedef unsigned int uint; typedef unsigned int uint;
typedef unsigned long ulong;
#define as(ar) (sizeof(ar)/sizeof(ar[0])) #define as(ar) (sizeof(ar)/sizeof(ar[0]))

View File

@ -953,7 +953,7 @@ parse_date( const char *str )
struct tm datetime; struct tm datetime;
memset( &datetime, 0, sizeof(datetime) ); memset( &datetime, 0, sizeof(datetime) );
if (!(end = strptime( str, "%d-%b-%Y %H:%M:%S ", &datetime ))) if (!(end = strptime( str, "%e-%b-%Y %H:%M:%S ", &datetime )))
return -1; return -1;
if ((date = timegm( &datetime )) == -1) if ((date = timegm( &datetime )) == -1)
return -1; return -1;
@ -1203,17 +1203,16 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
return RESP_OK; return RESP_OK;
} }
static int parse_list_rsp_p1( imap_store_t *, list_t *, char * );
static int parse_list_rsp_p2( imap_store_t *, list_t *, char * ); static int parse_list_rsp_p2( imap_store_t *, list_t *, char * );
static int static int
parse_list_rsp( imap_store_t *ctx, list_t *list, char *cmd ) parse_list_rsp( imap_store_t *ctx, list_t *list, char *cmd )
{ {
char *arg;
list_t *lp; list_t *lp;
if (!is_list( list )) { if (!is_list( list )) {
free_list( list ); free_list( list );
bad_list:
error( "IMAP error: malformed LIST response\n" ); error( "IMAP error: malformed LIST response\n" );
return LIST_BAD; return LIST_BAD;
} }
@ -1223,10 +1222,19 @@ parse_list_rsp( imap_store_t *ctx, list_t *list, char *cmd )
return LIST_OK; return LIST_OK;
} }
free_list( list ); free_list( list );
if (!(arg = next_arg( &cmd ))) return parse_list( ctx, cmd, parse_list_rsp_p1 );
goto bad_list; }
if (!ctx->delimiter[0])
ctx->delimiter[0] = arg[0]; static int
parse_list_rsp_p1( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED )
{
if (!is_opt_atom( list )) {
error( "IMAP error: malformed LIST response\n" );
free_list( list );
return LIST_BAD;
}
if (!ctx->delimiter[0] && is_atom( list ))
ctx->delimiter[0] = list->val[0];
return parse_list( ctx, cmd, parse_list_rsp_p2 ); return parse_list( ctx, cmd, parse_list_rsp_p2 );
} }
@ -1873,7 +1881,7 @@ ensure_password( imap_server_conf_t *srvc )
if (cmd) { if (cmd) {
FILE *fp; FILE *fp;
int ret; int ret;
char buffer[80]; char buffer[2048]; // Hopefully more than enough room for XOAUTH2, etc. tokens
if (*cmd == '+') { if (*cmd == '+') {
flushn(); flushn();
@ -2079,7 +2087,7 @@ done_sasl_auth( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response )
int rc = sasl_client_step( ctx->sasl, NULL, 0, &interact, &out, &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) if (process_sasl_step( ctx, rc, NULL, 0, interact, &out, &out_len ) < 0)
warn( "Warning: SASL reported failure despite successful IMAP authentication. Ignoring...\n" ); warn( "Warning: SASL reported failure despite successful IMAP authentication. Ignoring...\n" );
else if (out) else if (out_len > 0)
warn( "Warning: SASL wants more steps despite successful IMAP authentication. Ignoring...\n" ); warn( "Warning: SASL wants more steps despite successful IMAP authentication. Ignoring...\n" );
} }

View File

@ -109,6 +109,7 @@ sub type_to_format($)
{ {
$_ = shift; $_ = shift;
s/xint /\%\#x/g; s/xint /\%\#x/g;
s/uint /\%u/g;
s/int /\%d/g; s/int /\%d/g;
s/const char \*/\%s/g; s/const char \*/\%s/g;
return $_; return $_;

View File

@ -267,7 +267,7 @@ with DOS/Windows file systems.
.TP .TP
\fBSubFolders\fR \fBVerbatim\fR|\fBMaildir++\fR|\fBLegacy\fR \fBSubFolders\fR \fBVerbatim\fR|\fBMaildir++\fR|\fBLegacy\fR
The on-disk folder naming style used for hierarchical mailboxes. The on-disk folder naming style used for hierarchical mailboxes.
This has option has no effect when \fBFlatten\fR is used. This option has no effect when \fBFlatten\fR is used.
.br .br
Suppose mailboxes with the canonical paths \fBtop/sub/subsub\fR and Suppose mailboxes with the canonical paths \fBtop/sub/subsub\fR and
\fBINBOX/sub/subsub\fR, the styles will yield the following on-disk paths: \fBINBOX/sub/subsub\fR, the styles will yield the following on-disk paths:
@ -601,12 +601,13 @@ which in turn are overridden by command line switches.
.. ..
.TP .TP
\fBSyncState\fR {\fB*\fR|\fIpath\fR} \fBSyncState\fR {\fB*\fR|\fIpath\fR}
Set the location of this Channel's synchronization state files. \fB*\fR means Set the location of this Channel's synchronization state files.
that the state should be saved in a file named .mbsyncstate in the \fB*\fR means that the state should be saved in a file named .mbsyncstate
Slave mailbox itself; this has the advantage that you needn't to care for the in the Slave mailbox itself; this has the advantage that you do not need
state file if you delete the mailbox, but it works only with Maildir mailboxes, to handle the state file separately if you delete the mailbox, but it works
obviously. Otherwise this is interpreted as a string to prepend to the Slave only with Maildir mailboxes, obviously.
mailbox name to make up a complete path. Otherwise this is interpreted as a string to prepend to the Slave mailbox
name to make up a complete path.
.br .br
This option can be used outside any section for a global effect. In this case 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 the appended string is made up according to the pattern

View File

@ -63,6 +63,34 @@ socket_fail( conn_t *conn )
} }
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
static void ATTR_PRINTFLIKE(1, 2)
print_ssl_errors( const char *fmt, ... )
{
char *action;
va_list va;
ulong err;
va_start( va, fmt );
nfvasprintf( &action, fmt, va );
va_end( va );
while ((err = ERR_get_error()))
error( "Error while %s: %s\n", action, ERR_error_string( err, 0 ) );
free( action );
}
static int
print_ssl_socket_errors( const char *func, conn_t *conn )
{
ulong err;
int num = 0;
while ((err = ERR_get_error())) {
error( "Socket error: secure %s %s: %s\n", func, conn->name, ERR_error_string( err, 0 ) );
num++;
}
return num;
}
static int static int
ssl_return( const char *func, conn_t *conn, int ret ) ssl_return( const char *func, conn_t *conn, int ret )
{ {
@ -76,9 +104,12 @@ ssl_return( const char *func, conn_t *conn, int ret )
FALLTHROUGH FALLTHROUGH
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
return 0; return 0;
case SSL_ERROR_SYSCALL:
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
if (!(err = ERR_get_error())) { print_ssl_socket_errors( func, conn );
break;
case SSL_ERROR_SYSCALL:
if (print_ssl_socket_errors( func, conn ))
break;
if (ret == 0) { if (ret == 0) {
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
/* Callers take the short path out, so signal higher layers from here. */ /* Callers take the short path out, so signal higher layers from here. */
@ -87,9 +118,6 @@ ssl_return( const char *func, conn_t *conn, int ret )
return -1; return -1;
} }
sys_error( "Socket error: secure %s %s", func, conn->name ); sys_error( "Socket error: secure %s %s", func, conn->name );
} else {
error( "Socket error: secure %s %s: %s\n", func, conn->name, ERR_error_string( err, 0 ) );
}
break; break;
default: default:
error( "Socket error: secure %s %s: unhandled SSL error %d\n", func, conn->name, err ); error( "Socket error: secure %s %s: unhandled SSL error %d\n", func, conn->name, err );
@ -176,22 +204,29 @@ verify_cert_host( const server_conf_t *conf, conn_t *sock )
trusted = (STACK_OF(X509_OBJECT) *)sock->conf->trusted_certs; trusted = (STACK_OF(X509_OBJECT) *)sock->conf->trusted_certs;
for (i = 0; i < sk_X509_OBJECT_num( trusted ); i++) { for (i = 0; i < sk_X509_OBJECT_num( trusted ); i++) {
if (!X509_cmp( cert, X509_OBJECT_get0_X509( sk_X509_OBJECT_value( trusted, i ) ) )) if (!X509_cmp( cert, X509_OBJECT_get0_X509( sk_X509_OBJECT_value( trusted, i ) ) )) {
X509_free( cert );
return 0; return 0;
} }
}
err = SSL_get_verify_result( sock->ssl ); err = SSL_get_verify_result( sock->ssl );
if (err != X509_V_OK) { if (err != X509_V_OK) {
error( "SSL error connecting %s: %s\n", sock->name, X509_verify_cert_error_string( err ) ); error( "SSL error connecting %s: %s\n", sock->name, X509_verify_cert_error_string( err ) );
X509_free( cert );
return -1; return -1;
} }
if (!conf->host) { if (!conf->host) {
error( "SSL error connecting %s: Neither host nor matching certificate specified\n", sock->name ); error( "SSL error connecting %s: Neither host nor matching certificate specified\n", sock->name );
X509_free( cert );
return -1; return -1;
} }
return verify_hostname( cert, conf->host ); int ret = verify_hostname( cert, conf->host );
X509_free( cert );
return ret;
} }
static int static int
@ -203,7 +238,15 @@ init_ssl_ctx( const server_conf_t *conf )
if (conf->SSLContext) if (conf->SSLContext)
return conf->ssl_ctx_valid; return conf->ssl_ctx_valid;
mconf->SSLContext = SSL_CTX_new( SSLv23_client_method() ); #if OPENSSL_VERSION_NUMBER >= 0x10100000L
const SSL_METHOD *method = TLS_client_method();
#else
const SSL_METHOD *method = SSLv23_client_method();
#endif
if (!(mconf->SSLContext = SSL_CTX_new( method ))) {
print_ssl_errors( "initializing SSL context" );
return 0;
}
if (!(conf->ssl_versions & SSLv3)) if (!(conf->ssl_versions & SSLv3))
options |= SSL_OP_NO_SSLv3; options |= SSL_OP_NO_SSLv3;
@ -221,25 +264,24 @@ init_ssl_ctx( const server_conf_t *conf )
SSL_CTX_set_options( mconf->SSLContext, options ); SSL_CTX_set_options( mconf->SSLContext, options );
if (conf->cert_file && !SSL_CTX_load_verify_locations( mconf->SSLContext, conf->cert_file, 0 )) { if (conf->cert_file && !SSL_CTX_load_verify_locations( mconf->SSLContext, conf->cert_file, 0 )) {
error( "Error while loading certificate file '%s': %s\n", print_ssl_errors( "loading certificate file '%s'", conf->cert_file );
conf->cert_file, ERR_error_string( ERR_get_error(), 0 ) );
return 0; return 0;
} }
mconf->trusted_certs = (_STACK *)sk_X509_OBJECT_dup( X509_STORE_get0_objects( SSL_CTX_get_cert_store( mconf->SSLContext ) ) ); mconf->trusted_certs = (_STACK *)sk_X509_OBJECT_dup( X509_STORE_get0_objects( SSL_CTX_get_cert_store( mconf->SSLContext ) ) );
if (mconf->system_certs && !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", ulong err;
ERR_error_string( ERR_get_error(), 0 ) ); while ((err = ERR_get_error()))
warn( "Warning: Unable to load default certificate files: %s\n", ERR_error_string( err, 0 ) );
}
SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_NONE, NULL ); SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_NONE, NULL );
if (conf->client_certfile && !SSL_CTX_use_certificate_chain_file( mconf->SSLContext, conf->client_certfile)) { if (conf->client_certfile && !SSL_CTX_use_certificate_chain_file( mconf->SSLContext, conf->client_certfile)) {
error( "Error while loading client certificate file '%s': %s\n", print_ssl_errors( "loading client certificate file '%s'", conf->client_certfile );
conf->client_certfile, ERR_error_string( ERR_get_error(), 0 ) );
return 0; return 0;
} }
if (conf->client_keyfile && !SSL_CTX_use_PrivateKey_file( mconf->SSLContext, conf->client_keyfile, SSL_FILETYPE_PEM)) { if (conf->client_keyfile && !SSL_CTX_use_PrivateKey_file( mconf->SSLContext, conf->client_keyfile, SSL_FILETYPE_PEM)) {
error( "Error while loading client private key '%s': %s\n", print_ssl_errors( "loading client private key '%s'", conf->client_keyfile );
conf->client_keyfile, ERR_error_string( ERR_get_error(), 0 ) );
return 0; return 0;
} }
@ -270,10 +312,21 @@ socket_start_tls( conn_t *conn, void (*cb)( int ok, void *aux ) )
} }
init_wakeup( &conn->ssl_fake, ssl_fake_cb, conn ); init_wakeup( &conn->ssl_fake, ssl_fake_cb, conn );
conn->ssl = SSL_new( ((server_conf_t *)conn->conf)->SSLContext ); if (!(conn->ssl = SSL_new( ((server_conf_t *)conn->conf)->SSLContext ))) {
if (ssl_return( "set server name", conn, SSL_set_tlsext_host_name( conn->ssl, conn->conf->host ) ) < 0) print_ssl_errors( "initializing SSL connection" );
start_tls_p3( conn, 0 );
return; return;
SSL_set_fd( conn->ssl, conn->fd ); }
if (!SSL_set_tlsext_host_name( conn->ssl, conn->conf->host )) {
print_ssl_errors( "setting SSL server host name" );
start_tls_p3( conn, 0 );
return;
}
if (!SSL_set_fd( conn->ssl, conn->fd )) {
print_ssl_errors( "setting SSL socket fd" );
start_tls_p3( conn, 0 );
return;
}
SSL_set_mode( conn->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER ); SSL_set_mode( conn->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER );
socket_expect_read( conn, 1 ); socket_expect_read( conn, 1 );
conn->state = SCK_STARTTLS; conn->state = SCK_STARTTLS;
@ -545,8 +598,10 @@ static void
socket_connected( conn_t *conn ) socket_connected( conn_t *conn )
{ {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (conn->addrs) {
freeaddrinfo( conn->addrs ); freeaddrinfo( conn->addrs );
conn->addrs = 0; conn->addrs = 0;
}
#endif #endif
conf_notifier( &conn->notify, 0, POLLIN ); conf_notifier( &conn->notify, 0, POLLIN );
socket_expect_read( conn, 0 ); socket_expect_read( conn, 0 );