[BACK]Return to packet.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/packet.c between version 1.204 and 1.205

version 1.204, 2015/01/28 21:15:47 version 1.205, 2015/01/30 01:13:33
Line 266 
Line 266 
         const struct sshcipher *none = cipher_by_name("none");          const struct sshcipher *none = cipher_by_name("none");
         int r;          int r;
   
         if (none == NULL)          if (none == NULL) {
                 fatal("%s: cannot load cipher 'none'", __func__);                  error("%s: cannot load cipher 'none'", __func__);
                   return NULL;
           }
         if (ssh == NULL)          if (ssh == NULL)
                 ssh = ssh_alloc_session_state();                  ssh = ssh_alloc_session_state();
         if (ssh == NULL)          if (ssh == NULL) {
                 fatal("%s: cound not allocate state", __func__);                  error("%s: cound not allocate state", __func__);
                   return NULL;
           }
         state = ssh->state;          state = ssh->state;
         state->connection_in = fd_in;          state->connection_in = fd_in;
         state->connection_out = fd_out;          state->connection_out = fd_out;
         if ((r = cipher_init(&state->send_context, none,          if ((r = cipher_init(&state->send_context, none,
             (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 ||              (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 ||
             (r = cipher_init(&state->receive_context, none,              (r = cipher_init(&state->receive_context, none,
             (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0)              (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) {
                 fatal("%s: cipher_init failed: %s", __func__, ssh_err(r));                  error("%s: cipher_init failed: %s", __func__, ssh_err(r));
                   return NULL;
           }
         state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL;          state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL;
         deattack_init(&state->deattack);          deattack_init(&state->deattack);
         return ssh;          return ssh;
Line 882 
Line 888 
   
         /*          /*
          * Note that the packet is now only buffered in output.  It won't be           * Note that the packet is now only buffered in output.  It won't be
          * actually sent until packet_write_wait or packet_write_poll is           * actually sent until ssh_packet_write_wait or ssh_packet_write_poll
          * called.           * is called.
          */           */
         r = 0;          r = 0;
  out:   out:
Line 1252 
Line 1258 
         if (setp == NULL)          if (setp == NULL)
                 return SSH_ERR_ALLOC_FAIL;                  return SSH_ERR_ALLOC_FAIL;
   
         /* Since we are blocking, ensure that all written packets have been sent. */          /*
         ssh_packet_write_wait(ssh);           * Since we are blocking, ensure that all written packets have
            * been sent.
            */
           if ((r = ssh_packet_write_wait(ssh)) != 0)
                   return r;
   
         /* Stay in the loop until we have received a complete packet. */          /* Stay in the loop until we have received a complete packet. */
         for (;;) {          for (;;) {
Line 1339 
Line 1349 
  * that given, and gives a fatal error and exits if there is a mismatch.   * that given, and gives a fatal error and exits if there is a mismatch.
  */   */
   
 void  int
 ssh_packet_read_expect(struct ssh *ssh, int expected_type)  ssh_packet_read_expect(struct ssh *ssh, u_int expected_type)
 {  {
         int type;          int r;
           u_char type;
   
         type = ssh_packet_read(ssh);          if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
         if (type != expected_type)                  return r;
                 ssh_packet_disconnect(ssh,          if (type != expected_type) {
                   if ((r = sshpkt_disconnect(ssh,
                     "Protocol error: expected packet type %d, got %d",                      "Protocol error: expected packet type %d, got %d",
                     expected_type, type);                      expected_type, type)) != 0)
                           return r;
                   return SSH_ERR_PROTOCOL_ERROR;
           }
           return 0;
 }  }
   
 /* Checks if a full packet is available in the data received so far via  /* Checks if a full packet is available in the data received so far via
Line 1365 
Line 1381 
 {  {
         struct session_state *state = ssh->state;          struct session_state *state = ssh->state;
         u_int len, padded_len;          u_int len, padded_len;
           const char *emsg;
         const u_char *cp;          const u_char *cp;
         u_char *p;          u_char *p;
         u_int checksum, stored_checksum;          u_int checksum, stored_checksum;
Line 1377 
Line 1394 
                 return 0;                  return 0;
         /* Get length of incoming packet. */          /* Get length of incoming packet. */
         len = PEEK_U32(sshbuf_ptr(state->input));          len = PEEK_U32(sshbuf_ptr(state->input));
         if (len < 1 + 2 + 2 || len > 256 * 1024)          if (len < 1 + 2 + 2 || len > 256 * 1024) {
                 ssh_packet_disconnect(ssh, "Bad packet length %u.",                  if ((r = sshpkt_disconnect(ssh, "Bad packet length %u",
                     len);                      len)) != 0)
                           return r;
                   return SSH_ERR_CONN_CORRUPT;
           }
         padded_len = (len + 8) & ~7;          padded_len = (len + 8) & ~7;
   
         /* Check if the packet has been entirely received. */          /* Check if the packet has been entirely received. */
Line 1398 
Line 1418 
          * Ariel Futoransky(futo@core-sdi.com)           * Ariel Futoransky(futo@core-sdi.com)
          */           */
         if (!state->receive_context.plaintext) {          if (!state->receive_context.plaintext) {
                   emsg = NULL;
                 switch (detect_attack(&state->deattack,                  switch (detect_attack(&state->deattack,
                     sshbuf_ptr(state->input), padded_len)) {                      sshbuf_ptr(state->input), padded_len)) {
                 case DEATTACK_OK:                  case DEATTACK_OK:
                         break;                          break;
                 case DEATTACK_DETECTED:                  case DEATTACK_DETECTED:
                         ssh_packet_disconnect(ssh,                          emsg = "crc32 compensation attack detected";
                             "crc32 compensation attack: network attack detected"                          break;
                         );  
                 case DEATTACK_DOS_DETECTED:                  case DEATTACK_DOS_DETECTED:
                         ssh_packet_disconnect(ssh,                          emsg = "deattack denial of service detected";
                             "deattack denial of service detected");                          break;
                 default:                  default:
                         ssh_packet_disconnect(ssh, "deattack error");                          emsg = "deattack error";
                           break;
                 }                  }
                   if (emsg != NULL) {
                           error("%s", emsg);
                           if ((r = sshpkt_disconnect(ssh, "%s", emsg)) != 0 ||
                               (r = ssh_packet_write_wait(ssh)) != 0)
                                           return r;
                           return SSH_ERR_CONN_CORRUPT;
                   }
         }          }
   
         /* Decrypt data to incoming_packet. */          /* Decrypt data to incoming_packet. */
Line 1439 
Line 1467 
                 goto out;                  goto out;
   
         /* Test check bytes. */          /* Test check bytes. */
         if (len != sshbuf_len(state->incoming_packet))          if (len != sshbuf_len(state->incoming_packet)) {
                 ssh_packet_disconnect(ssh,                  error("%s: len %d != sshbuf_len %zd", __func__,
                     "packet_read_poll1: len %d != sshbuf_len %zd.",  
                     len, sshbuf_len(state->incoming_packet));                      len, sshbuf_len(state->incoming_packet));
                   if ((r = sshpkt_disconnect(ssh, "invalid packet length")) != 0 ||
                       (r = ssh_packet_write_wait(ssh)) != 0)
                           return r;
                   return SSH_ERR_CONN_CORRUPT;
           }
   
         cp = sshbuf_ptr(state->incoming_packet) + len - 4;          cp = sshbuf_ptr(state->incoming_packet) + len - 4;
         stored_checksum = PEEK_U32(cp);          stored_checksum = PEEK_U32(cp);
         if (checksum != stored_checksum)          if (checksum != stored_checksum) {
                 ssh_packet_disconnect(ssh,                  error("Corrupted check bytes on input");
                     "Corrupted check bytes on input.");                  if ((r = sshpkt_disconnect(ssh, "connection corrupted")) != 0 ||
                       (r = ssh_packet_write_wait(ssh)) != 0)
                           return r;
                   return SSH_ERR_CONN_CORRUPT;
           }
         if ((r = sshbuf_consume_end(state->incoming_packet, 4)) < 0)          if ((r = sshbuf_consume_end(state->incoming_packet, 4)) < 0)
                 goto out;                  goto out;
   
Line 1466 
Line 1502 
         state->p_read.bytes += padded_len + 4;          state->p_read.bytes += padded_len + 4;
         if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)          if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
                 goto out;                  goto out;
         if (*typep < SSH_MSG_MIN || *typep > SSH_MSG_MAX)          if (*typep < SSH_MSG_MIN || *typep > SSH_MSG_MAX) {
                 ssh_packet_disconnect(ssh,                  error("Invalid ssh1 packet type: %d", *typep);
                     "Invalid ssh1 packet type: %d", *typep);                  if ((r = sshpkt_disconnect(ssh, "invalid packet type")) != 0 ||
                       (r = ssh_packet_write_wait(ssh)) != 0)
                           return r;
                   return SSH_ERR_PROTOCOL_ERROR;
           }
         r = 0;          r = 0;
  out:   out:
         return r;          return r;
Line 1622 
Line 1662 
                 if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)                  if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
                         goto out;                          goto out;
         }          }
         /* XXX now it's safe to use fatal/packet_disconnect */  
         if (seqnr_p != NULL)          if (seqnr_p != NULL)
                 *seqnr_p = state->p_read.seqnr;                  *seqnr_p = state->p_read.seqnr;
         if (++state->p_read.seqnr == 0)          if (++state->p_read.seqnr == 0)
Line 1636 
Line 1675 
         /* get padlen */          /* get padlen */
         padlen = sshbuf_ptr(state->incoming_packet)[4];          padlen = sshbuf_ptr(state->incoming_packet)[4];
         DBG(debug("input: padlen %d", padlen));          DBG(debug("input: padlen %d", padlen));
         if (padlen < 4)          if (padlen < 4) {
                 ssh_packet_disconnect(ssh,                  if ((r = sshpkt_disconnect(ssh,
                     "Corrupted padlen %d on input.", padlen);                      "Corrupted padlen %d on input.", padlen)) != 0 ||
                       (r = ssh_packet_write_wait(ssh)) != 0)
                           return r;
                   return SSH_ERR_CONN_CORRUPT;
           }
   
         /* skip packet size + padlen, discard padding */          /* skip packet size + padlen, discard padding */
         if ((r = sshbuf_consume(state->incoming_packet, 4 + 1)) != 0 ||          if ((r = sshbuf_consume(state->incoming_packet, 4 + 1)) != 0 ||
Line 1665 
Line 1708 
          */           */
         if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)          if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
                 goto out;                  goto out;
         if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN)          if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) {
                 ssh_packet_disconnect(ssh,                  if ((r = sshpkt_disconnect(ssh,
                     "Invalid ssh2 packet type: %d", *typep);                      "Invalid ssh2 packet type: %d", *typep)) != 0 ||
                       (r = ssh_packet_write_wait(ssh)) != 0)
                           return r;
                   return SSH_ERR_PROTOCOL_ERROR;
           }
         if (*typep == SSH2_MSG_NEWKEYS)          if (*typep == SSH2_MSG_NEWKEYS)
                 r = ssh_set_newkeys(ssh, MODE_IN);                  r = ssh_set_newkeys(ssh, MODE_IN);
         else if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side)          else if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side)
Line 1804 
Line 1851 
  * message is printed immediately, but only if the client is being executed   * message is printed immediately, but only if the client is being executed
  * in verbose mode.  These messages are primarily intended to ease debugging   * in verbose mode.  These messages are primarily intended to ease debugging
  * authentication problems.   The length of the formatted message must not   * authentication problems.   The length of the formatted message must not
  * exceed 1024 bytes.  This will automatically call packet_write_wait.   * exceed 1024 bytes.  This will automatically call ssh_packet_write_wait.
  */   */
   
 void  void
 ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)  ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
 {  {
Line 1834 
Line 1880 
                     (r = sshpkt_send(ssh)) != 0)                      (r = sshpkt_send(ssh)) != 0)
                         fatal("%s: %s", __func__, ssh_err(r));                          fatal("%s: %s", __func__, ssh_err(r));
         }          }
         ssh_packet_write_wait(ssh);          if ((r = ssh_packet_write_wait(ssh)) != 0)
                   fatal("%s: %s", __func__, ssh_err(r));
 }  }
   
 /*  /*
    * Pretty-print connection-terminating errors and exit.
    */
   void
   sshpkt_fatal(struct ssh *ssh, const char *tag, int r)
   {
           switch (r) {
           case SSH_ERR_CONN_CLOSED:
                   logit("Connection closed by %.200s", ssh_remote_ipaddr(ssh));
                   cleanup_exit(255);
           case SSH_ERR_CONN_TIMEOUT:
                   logit("Connection to %.200s timed out while "
                       "waiting to write", ssh_remote_ipaddr(ssh));
                   cleanup_exit(255);
           default:
                   fatal("%s%sConnection to %.200s: %s",
                       tag != NULL ? tag : "", tag != NULL ? ": " : "",
                       ssh_remote_ipaddr(ssh), ssh_err(r));
           }
   }
   
   /*
  * Logs the error plus constructs and sends a disconnect packet, closes the   * Logs the error plus constructs and sends a disconnect packet, closes the
  * connection, and exits.  This function never returns. The error message   * connection, and exits.  This function never returns. The error message
  * should not contain a newline.  The length of the formatted message must   * should not contain a newline.  The length of the formatted message must
  * not exceed 1024 bytes.   * not exceed 1024 bytes.
  */   */
   
 void  void
 ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...)  ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...)
 {  {
Line 1867 
Line 1934 
         /* Display the error locally */          /* Display the error locally */
         logit("Disconnecting: %.100s", buf);          logit("Disconnecting: %.100s", buf);
   
         /* Send the disconnect message to the other side, and wait for it to get sent. */          /*
         if (compat20) {           * Send the disconnect message to the other side, and wait
                 if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||           * for it to get sent.
                     (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||           */
                     (r = sshpkt_put_cstring(ssh, buf)) != 0 ||          if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0)
                     (r = sshpkt_put_cstring(ssh, "")) != 0 ||                  sshpkt_fatal(ssh, __func__, r);
                     (r = sshpkt_send(ssh)) != 0)  
                         fatal("%s: %s", __func__, ssh_err(r));  
         } else {  
                 if ((r = sshpkt_start(ssh, SSH_MSG_DISCONNECT)) != 0 ||  
                     (r = sshpkt_put_cstring(ssh, buf)) != 0 ||  
                     (r = sshpkt_send(ssh)) != 0)  
                         fatal("%s: %s", __func__, ssh_err(r));  
         }  
         ssh_packet_write_wait(ssh);  
   
           if ((r = ssh_packet_write_wait(ssh)) != 0)
                   sshpkt_fatal(ssh, __func__, r);
   
         /* Close the connection. */          /* Close the connection. */
         ssh_packet_close(ssh);          ssh_packet_close(ssh);
         cleanup_exit(255);          cleanup_exit(255);
 }  }
   
 /* Checks if there is any buffered output, and tries to write some of the output. */  /*
    * Checks if there is any buffered output, and tries to write some of
 void   * the output.
    */
   int
 ssh_packet_write_poll(struct ssh *ssh)  ssh_packet_write_poll(struct ssh *ssh)
 {  {
         struct session_state *state = ssh->state;          struct session_state *state = ssh->state;
Line 1903 
Line 1966 
                     sshbuf_ptr(state->output), len, &cont);                      sshbuf_ptr(state->output), len, &cont);
                 if (len == -1) {                  if (len == -1) {
                         if (errno == EINTR || errno == EAGAIN)                          if (errno == EINTR || errno == EAGAIN)
                                 return;                                  return 0;
                         fatal("Write failed: %.100s", strerror(errno));                          return SSH_ERR_SYSTEM_ERROR;
                 }                  }
                 if (len == 0 && !cont)                  if (len == 0 && !cont)
                         fatal("Write connection closed");                          return SSH_ERR_CONN_CLOSED;
                 if ((r = sshbuf_consume(state->output, len)) != 0)                  if ((r = sshbuf_consume(state->output, len)) != 0)
                         fatal("%s: %s", __func__, ssh_err(r));                          return r;
         }          }
           return 0;
 }  }
   
 /*  /*
  * Calls packet_write_poll repeatedly until all pending output data has been   * Calls packet_write_poll repeatedly until all pending output data has been
  * written.   * written.
  */   */
   int
 void  
 ssh_packet_write_wait(struct ssh *ssh)  ssh_packet_write_wait(struct ssh *ssh)
 {  {
         fd_set *setp;          fd_set *setp;
         int ret, ms_remain = 0;          int ret, r, ms_remain = 0;
         struct timeval start, timeout, *timeoutp = NULL;          struct timeval start, timeout, *timeoutp = NULL;
         struct session_state *state = ssh->state;          struct session_state *state = ssh->state;
   
         setp = (fd_set *)calloc(howmany(state->connection_out + 1,          setp = (fd_set *)calloc(howmany(state->connection_out + 1,
             NFDBITS), sizeof(fd_mask));              NFDBITS), sizeof(fd_mask));
         if (setp == NULL)          if (setp == NULL)
                 fatal("%s: calloc failed", __func__);                  return SSH_ERR_ALLOC_FAIL;
         ssh_packet_write_poll(ssh);          ssh_packet_write_poll(ssh);
         while (ssh_packet_have_data_to_write(ssh)) {          while (ssh_packet_have_data_to_write(ssh)) {
                 memset(setp, 0, howmany(state->connection_out + 1,                  memset(setp, 0, howmany(state->connection_out + 1,
Line 1959 
Line 2022 
                         }                          }
                 }                  }
                 if (ret == 0) {                  if (ret == 0) {
                         logit("Connection to %.200s timed out while "                          free(setp);
                             "waiting to write", ssh_remote_ipaddr(ssh));                          return SSH_ERR_CONN_TIMEOUT;
                         cleanup_exit(255);  
                 }                  }
                 ssh_packet_write_poll(ssh);                  if ((r = ssh_packet_write_poll(ssh)) != 0) {
                           free(setp);
                           return r;
                   }
         }          }
         free(setp);          free(setp);
           return 0;
 }  }
   
 /* Returns true if there is buffered data to write to the connection. */  /* Returns true if there is buffered data to write to the connection. */

Legend:
Removed from v.1.204  
changed lines
  Added in v.1.205