From 6c959c3ee4bba035e6ad0e8e71cb7526f503e43b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 13 Dec 2014 18:01:52 +0100 Subject: [PATCH] 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). --- src/drv_imap.c | 49 ++++++++++++++++++++++++++----------------------- src/socket.c | 19 +++++++------------ src/socket.h | 9 +++++++++ 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/drv_imap.c b/src/drv_imap.c index f52992d..7f8f821 100644 --- 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 )) { + if (ctx->greeting == GreetingPending && !strcmp( "PREAUTH", arg )) { + parse_response_code( ctx, 0, cmd ); 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 )) { - 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 index b300910..56e041a 100644 --- a/src/socket.c +++ b/src/socket.c @@ -43,14 +43,6 @@ # include #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 index a420e49..20c3033 100644 --- a/src/socket.h +++ b/src/socket.h @@ -29,6 +29,15 @@ #include #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;