commit 6c959c3ee4bba035e6ad0e8e71cb7526f503e43b
parent 4f3ef54f3a261c2bf052899d647c6df46c0fd547
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Sat, 13 Dec 2014 18:01:52 +0100
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).
Diffstat:
3 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/src/drv_imap.c b/src/drv_imap.c
@@ -1203,10 +1203,9 @@ imap_socket_read( void *aux )
imap_store_t *ctx = (imap_store_t *)aux;
struct imap_cmd *cmdp, **pcmdp;
char *cmd, *arg, *arg1, *p;
- int resp, resp2, tag, greeted;
+ int resp, resp2, tag;
conn_iovec_t iov[2];
- greeted = ctx->greeting;
for (;;) {
if (ctx->parse_list_sts.level) {
resp = parse_list_continue( ctx, 0 );
@@ -1236,18 +1235,30 @@ imap_socket_read( void *aux )
break;
}
- if (!strcmp( "NAMESPACE", arg )) {
- resp = parse_list( ctx, cmd, parse_namespace_rsp );
- goto listret;
- } else if (ctx->greeting == GreetingPending && !strcmp( "PREAUTH", arg )) {
- ctx->greeting = GreetingPreauth;
+ if (ctx->greeting == GreetingPending && !strcmp( "PREAUTH", arg )) {
parse_response_code( ctx, 0, cmd );
+ ctx->greeting = GreetingPreauth;
+ dogreet:
+ imap_ref( ctx );
+ imap_open_store_greeted( ctx );
+ if (imap_deref( ctx ))
+ return;
} else if (!strcmp( "OK", arg )) {
- ctx->greeting = GreetingOk;
parse_response_code( ctx, 0, cmd );
+ if (ctx->greeting == GreetingPending) {
+ ctx->greeting = GreetingOk;
+ goto dogreet;
+ }
} else if (!strcmp( "BYE", arg )) {
- ctx->greeting = GreetingBad;
- parse_response_code( ctx, 0, cmd );
+ if (ctx->conn.state != SCK_CLOSING) {
+ ctx->conn.state = SCK_CLOSING;
+ ctx->greeting = GreetingBad;
+ 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 )) {
warn( "Warning from IMAP server: %s\n", cmd );
} else if (!strcmp( "BAD", arg )) {
@@ -1257,6 +1268,9 @@ imap_socket_read( void *aux )
} else if (!strcmp( "LIST", arg )) {
resp = parse_list( ctx, cmd, parse_list_rsp );
goto listret;
+ } else if (!strcmp( "NAMESPACE", arg )) {
+ resp = parse_list( ctx, cmd, parse_namespace_rsp );
+ goto listret;
} else if ((arg1 = next_arg( &cmd ))) {
if (!strcmp( "EXISTS", arg1 ))
ctx->gen.count = atoi( arg );
@@ -1270,12 +1284,6 @@ imap_socket_read( void *aux )
error( "IMAP error: unrecognized untagged response '%s'\n", arg );
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;
} else if (!ctx->in_progress) {
error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" );
@@ -1462,6 +1470,7 @@ imap_cleanup( void )
for (ctx = unowned; ctx; ctx = nctx) {
nctx = ctx->next;
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" );
}
}
@@ -1470,7 +1479,7 @@ static void
imap_cleanup_p2( imap_store_t *ctx,
struct imap_cmd *cmd ATTR_UNUSED, int response )
{
- if (response != RESP_CANCEL)
+ if (response == RESP_NO)
imap_cancel_store( &ctx->gen );
}
@@ -1583,12 +1592,6 @@ imap_open_store_tlsstarted1( int ok, void *aux )
static void
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)
imap_exec( ctx, 0, imap_open_store_p2, "CAPABILITY" );
else
diff --git a/src/socket.c b/src/socket.c
@@ -43,14 +43,6 @@
# include <openssl/x509v3.h>
#endif
-enum {
- SCK_CONNECTING,
-#ifdef HAVE_LIBSSL
- SCK_STARTTLS,
-#endif
- SCK_READY
-};
-
static void
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_SSL:
if (!(err = ERR_get_error())) {
- if (ret == 0)
- error( "Socket error: secure %s %s: unexpected EOF\n", func, conn->name );
- else
+ if (ret == 0) {
+ if (conn->state != SCK_CLOSING)
+ error( "Socket error: secure %s %s: unexpected EOF\n", func, conn->name );
+ } else {
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 ) );
}
@@ -588,7 +582,8 @@ do_read( conn_t *sock, char *buf, int len )
sys_error( "Socket error: read from %s", sock->name );
socket_fail( sock );
} else if (!n) {
- error( "Socket error: read from %s: unexpected EOF\n", sock->name );
+ if (sock->state != SCK_CLOSING)
+ error( "Socket error: read from %s: unexpected EOF\n", sock->name );
socket_fail( sock );
return -1;
}
diff --git a/src/socket.h b/src/socket.h
@@ -29,6 +29,15 @@
#include <zlib.h>
#endif
+enum {
+ SCK_CONNECTING,
+#ifdef HAVE_LIBSSL
+ SCK_STARTTLS,
+#endif
+ SCK_READY,
+ SCK_CLOSING
+};
+
#ifdef HAVE_LIBSSL
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;