Blob Blame History Raw
--- contrib/mod_sftp/kbdint.c
+++ contrib/mod_sftp/kbdint.c
@@ -254,6 +254,77 @@ int sftp_kbdint_send_challenge(const cha
   return res;
 }
 
+static struct ssh2_packet *read_response_packet(pool *p) {
+  struct ssh2_packet *pkt = NULL;
+
+  /* Keep looping until we get the desired message, or we time out. */
+  while (pkt == NULL) {
+    int res;
+    char mesg_type;
+
+    pr_signals_handle();
+
+    pkt = sftp_ssh2_packet_create(kbdint_pool);
+    res = sftp_ssh2_packet_read(sftp_conn->rfd, pkt);
+    if (res < 0) {
+      int xerrno = errno;
+
+      destroy_pool(pkt->pool);
+
+      errno = xerrno;
+      return NULL;
+    }
+
+    pr_response_clear(&resp_list);
+    pr_response_clear(&resp_err_list);
+
+    /* Per RFC 4253, Section 11, DEBUG, DISCONNECT, IGNORE, and UNIMPLEMENTED
+     * messages can occur at any time, even during KEX.  We have to be prepared
+     * for this, and Do The Right Thing(tm).
+     */
+
+    mesg_type = sftp_ssh2_packet_get_mesg_type(pkt);
+
+    switch (mesg_type) {
+      case SFTP_SSH2_MSG_DEBUG:
+        sftp_ssh2_packet_handle_debug(pkt);
+        pkt = NULL;
+        break;
+
+      case SFTP_SSH2_MSG_DISCONNECT:
+        sftp_ssh2_packet_handle_disconnect(pkt);
+        pkt = NULL;
+        break;
+
+      case SFTP_SSH2_MSG_IGNORE:
+        sftp_ssh2_packet_handle_ignore(pkt);
+        pkt = NULL;
+        break;
+
+      case SFTP_SSH2_MSG_UNIMPLEMENTED:
+        sftp_ssh2_packet_handle_unimplemented(pkt);
+        pkt = NULL;
+        break;
+
+      case SFTP_SSH2_MSG_USER_AUTH_INFO_RESP:
+        pr_trace_msg(trace_channel, 13,
+          "received expected %s message",
+          sftp_ssh2_packet_get_mesg_type_desc(mesg_type));
+        break;
+
+      default:
+        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+          "expecting USER_AUTH_INFO_RESP message, received %s (%d)",
+          sftp_ssh2_packet_get_mesg_type_desc(mesg_type), mesg_type);
+        destroy_pool(pkt->pool);
+        errno = EPERM;
+        return NULL;
+    }
+  }
+
+  return pkt;
+}
+
 int sftp_kbdint_recv_response(pool *p, uint32_t expected_count,
     uint32_t *rcvd_count, const char ***responses) {
   register unsigned int i;
@@ -261,9 +332,7 @@ int sftp_kbdint_recv_response(pool *p, u
   cmd_rec *cmd;
   array_header *list;
   uint32_t buflen, resp_count;
-  struct ssh2_packet *pkt;
-  char mesg_type;
-  int res;
+  struct ssh2_packet *pkt = NULL;
 
   if (p == NULL ||
       rcvd_count == NULL ||
@@ -272,28 +341,13 @@ int sftp_kbdint_recv_response(pool *p, u
     return -1;
   }
 
-  pkt = sftp_ssh2_packet_create(kbdint_pool);
-
-  res = sftp_ssh2_packet_read(sftp_conn->rfd, pkt);
-  if (res < 0) {
-    destroy_pool(pkt->pool);
-    return res;
+  pkt = read_response_packet(p);
+  if (pkt == NULL) {
+    return -1;
   }
 
-  pr_response_clear(&resp_list);
-  pr_response_clear(&resp_err_list);
   pr_response_set_pool(pkt->pool);
 
-  mesg_type = sftp_ssh2_packet_get_mesg_type(pkt);
-  if (mesg_type != SFTP_SSH2_MSG_USER_AUTH_INFO_RESP) {
-    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-      "expecting USER_AUTH_INFO_RESP message, received %s (%d)",
-      sftp_ssh2_packet_get_mesg_type_desc(mesg_type), mesg_type);
-    destroy_pool(pkt->pool);
-    errno = EPERM;
-    return -1;
-  }
-
   cmd = pr_cmd_alloc(pkt->pool, 2, pstrdup(pkt->pool, "USER_AUTH_INFO_RESP"));
   cmd->arg = "(data)";