소스 검색

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).
Oswald Buddenhagen 10 년 전
부모
커밋
6c959c3ee4
3개의 변경된 파일42개의 추가작업 그리고 35개의 파일을 삭제
  1. 26 23
      src/drv_imap.c
  2. 7 12
      src/socket.c
  3. 9 0
      src/socket.h

+ 26 - 23
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

+ 7 - 12
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;
 		}

+ 9 - 0
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;