fix handling of unsolicited BYE responses

they can come in at any time, after which we must expect the connection
to be closed (and not complain about it).
This commit is contained in:
Oswald Buddenhagen 2014-12-13 18:01:52 +01:00
parent 4f3ef54f3a
commit 6c959c3ee4
3 changed files with 42 additions and 35 deletions

View File

@ -1203,10 +1203,9 @@ imap_socket_read( void *aux )
imap_store_t *ctx = (imap_store_t *)aux; imap_store_t *ctx = (imap_store_t *)aux;
struct imap_cmd *cmdp, **pcmdp; struct imap_cmd *cmdp, **pcmdp;
char *cmd, *arg, *arg1, *p; char *cmd, *arg, *arg1, *p;
int resp, resp2, tag, greeted; int resp, resp2, tag;
conn_iovec_t iov[2]; conn_iovec_t iov[2];
greeted = ctx->greeting;
for (;;) { for (;;) {
if (ctx->parse_list_sts.level) { if (ctx->parse_list_sts.level) {
resp = parse_list_continue( ctx, 0 ); resp = parse_list_continue( ctx, 0 );
@ -1236,18 +1235,30 @@ imap_socket_read( void *aux )
break; break;
} }
if (!strcmp( "NAMESPACE", arg )) { if (ctx->greeting == GreetingPending && !strcmp( "PREAUTH", arg )) {
resp = parse_list( ctx, cmd, parse_namespace_rsp ); parse_response_code( ctx, 0, cmd );
goto listret;
} else if (ctx->greeting == GreetingPending && !strcmp( "PREAUTH", arg )) {
ctx->greeting = GreetingPreauth; ctx->greeting = GreetingPreauth;
parse_response_code( ctx, 0, cmd ); dogreet:
imap_ref( ctx );
imap_open_store_greeted( ctx );
if (imap_deref( ctx ))
return;
} else if (!strcmp( "OK", arg )) { } else if (!strcmp( "OK", arg )) {
parse_response_code( ctx, 0, cmd );
if (ctx->greeting == GreetingPending) {
ctx->greeting = GreetingOk; ctx->greeting = GreetingOk;
parse_response_code( ctx, 0, cmd ); goto dogreet;
}
} else if (!strcmp( "BYE", arg )) { } else if (!strcmp( "BYE", arg )) {
if (ctx->conn.state != SCK_CLOSING) {
ctx->conn.state = SCK_CLOSING;
ctx->greeting = GreetingBad; ctx->greeting = GreetingBad;
parse_response_code( ctx, 0, cmd ); error( "IMAP error: unexpected BYE response: %s\n", cmd );
}
/* We just wait for the server to close the connection now. */
} else if (ctx->greeting == GreetingPending) {
error( "IMAP error: bogus greeting response %s\n", arg );
break;
} else if (!strcmp( "NO", arg )) { } else if (!strcmp( "NO", arg )) {
warn( "Warning from IMAP server: %s\n", cmd ); warn( "Warning from IMAP server: %s\n", cmd );
} else if (!strcmp( "BAD", arg )) { } else if (!strcmp( "BAD", arg )) {
@ -1257,6 +1268,9 @@ imap_socket_read( void *aux )
} else if (!strcmp( "LIST", arg )) { } else if (!strcmp( "LIST", arg )) {
resp = parse_list( ctx, cmd, parse_list_rsp ); resp = parse_list( ctx, cmd, parse_list_rsp );
goto listret; goto listret;
} else if (!strcmp( "NAMESPACE", arg )) {
resp = parse_list( ctx, cmd, parse_namespace_rsp );
goto listret;
} else if ((arg1 = next_arg( &cmd ))) { } else if ((arg1 = next_arg( &cmd ))) {
if (!strcmp( "EXISTS", arg1 )) if (!strcmp( "EXISTS", arg1 ))
ctx->gen.count = atoi( arg ); ctx->gen.count = atoi( arg );
@ -1270,12 +1284,6 @@ imap_socket_read( void *aux )
error( "IMAP error: unrecognized untagged response '%s'\n", arg ); error( "IMAP error: unrecognized untagged response '%s'\n", arg );
break; /* this may mean anything, so prefer not to spam the log */ break; /* this may mean anything, so prefer not to spam the log */
} }
if (greeted == GreetingPending) {
imap_ref( ctx );
imap_open_store_greeted( ctx );
if (imap_deref( ctx ))
return;
}
continue; continue;
} else if (!ctx->in_progress) { } else if (!ctx->in_progress) {
error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" ); error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" );
@ -1462,6 +1470,7 @@ imap_cleanup( void )
for (ctx = unowned; ctx; ctx = nctx) { for (ctx = unowned; ctx; ctx = nctx) {
nctx = ctx->next; nctx = ctx->next;
set_bad_callback( ctx, (void (*)(void *))imap_cancel_store, ctx ); set_bad_callback( ctx, (void (*)(void *))imap_cancel_store, ctx );
((imap_store_t *)ctx)->conn.state = SCK_CLOSING;
imap_exec( (imap_store_t *)ctx, 0, imap_cleanup_p2, "LOGOUT" ); imap_exec( (imap_store_t *)ctx, 0, imap_cleanup_p2, "LOGOUT" );
} }
} }
@ -1470,7 +1479,7 @@ static void
imap_cleanup_p2( imap_store_t *ctx, imap_cleanup_p2( imap_store_t *ctx,
struct imap_cmd *cmd ATTR_UNUSED, int response ) struct imap_cmd *cmd ATTR_UNUSED, int response )
{ {
if (response != RESP_CANCEL) if (response == RESP_NO)
imap_cancel_store( &ctx->gen ); imap_cancel_store( &ctx->gen );
} }
@ -1583,12 +1592,6 @@ imap_open_store_tlsstarted1( int ok, void *aux )
static void static void
imap_open_store_greeted( imap_store_t *ctx ) imap_open_store_greeted( imap_store_t *ctx )
{ {
if (ctx->greeting == GreetingBad) {
error( "IMAP error: unknown greeting response\n" );
imap_open_store_bail( ctx );
return;
}
if (!ctx->caps) if (!ctx->caps)
imap_exec( ctx, 0, imap_open_store_p2, "CAPABILITY" ); imap_exec( ctx, 0, imap_open_store_p2, "CAPABILITY" );
else else

View File

@ -43,14 +43,6 @@
# include <openssl/x509v3.h> # include <openssl/x509v3.h>
#endif #endif
enum {
SCK_CONNECTING,
#ifdef HAVE_LIBSSL
SCK_STARTTLS,
#endif
SCK_READY
};
static void static void
socket_fail( conn_t *conn ) socket_fail( conn_t *conn )
{ {
@ -74,10 +66,12 @@ ssl_return( const char *func, conn_t *conn, int ret )
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
if (!(err = ERR_get_error())) { if (!(err = ERR_get_error())) {
if (ret == 0) if (ret == 0) {
if (conn->state != SCK_CLOSING)
error( "Socket error: secure %s %s: unexpected EOF\n", func, conn->name ); error( "Socket error: secure %s %s: unexpected EOF\n", func, conn->name );
else } else {
sys_error( "Socket error: secure %s %s", func, conn->name ); sys_error( "Socket error: secure %s %s", func, conn->name );
}
} else { } else {
error( "Socket error: secure %s %s: %s\n", func, conn->name, ERR_error_string( err, 0 ) ); error( "Socket error: secure %s %s: %s\n", func, conn->name, ERR_error_string( err, 0 ) );
} }
@ -588,6 +582,7 @@ do_read( conn_t *sock, char *buf, int len )
sys_error( "Socket error: read from %s", sock->name ); sys_error( "Socket error: read from %s", sock->name );
socket_fail( sock ); socket_fail( sock );
} else if (!n) { } else if (!n) {
if (sock->state != SCK_CLOSING)
error( "Socket error: read from %s: unexpected EOF\n", sock->name ); error( "Socket error: read from %s: unexpected EOF\n", sock->name );
socket_fail( sock ); socket_fail( sock );
return -1; return -1;

View File

@ -29,6 +29,15 @@
#include <zlib.h> #include <zlib.h>
#endif #endif
enum {
SCK_CONNECTING,
#ifdef HAVE_LIBSSL
SCK_STARTTLS,
#endif
SCK_READY,
SCK_CLOSING
};
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
typedef struct ssl_st SSL; typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX; typedef struct ssl_ctx_st SSL_CTX;