Esempio n. 1
0
END_TEST

START_TEST (parse_ext_addr_test) {
  const pr_netaddr_t *addr, *res;
  const char *msg; 

  res = proxy_ftp_msg_parse_ext_addr(NULL, NULL, NULL, 0, NULL);
  fail_unless(res == NULL, "Failed to handle null pool");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
    strerror(errno), errno);

  res = proxy_ftp_msg_parse_ext_addr(p, NULL, NULL, 0, NULL);
  fail_unless(res == NULL, "Failed to handle null msg");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got '%s' (%d)", EINVAL,
    strerror(errno), errno);

  msg = "foo";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, NULL, 0, NULL);
  fail_unless(res == NULL, "Failed to handle null addr");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
  fail_unless(addr != NULL, "Failed to get address for 127.0.0.1: %s",
    strerror(errno));

  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, 0, NULL);
  fail_unless(res == NULL, "Failed to handle bad network protocol");
  fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
    EPROTOTYPE, strerror(errno), errno);

  /* EPSV response formats */

  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle bad EPSV response");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  msg = "(foo";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle bad EPSV response");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  msg = "(foo)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle bad network protocol");
  fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
    EPROTOTYPE, strerror(errno), errno);

  msg = "(1)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle bad network protocol");
  fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
    EPROTOTYPE, strerror(errno), errno);

  msg = "(|4)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle bad network protocol");
  fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
    EPROTOTYPE, strerror(errno), errno);

  msg = "(|0)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle bad network protocol");
  fail_unless(errno == EPROTOTYPE, "Expected EPROTOTYPE (%d), got '%s' (%d)",
    EPROTOTYPE, strerror(errno), errno);

  msg = "(|1)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle bad network protocol");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

  msg = "(|2)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle bad network protocol");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

  /* Where the network protocol matches that of the address... */
  msg = "(|1|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle badly formatted message");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  msg = "(|1|1.2.3.4)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle badly formatted message");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  msg = "(|1|1.2.3.4|5)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle badly formatted message");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

  msg = "(|1|1.2.3.4|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));

  msg = "(||1.2.3.4|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));

  msg = "(||1.2.3.4|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, "all");
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));

  msg = "(||1.2.3.4|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, "1");
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));

  msg = "(|||5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));
  fail_unless(
    strcmp(pr_netaddr_get_ipstr(addr), pr_netaddr_get_ipstr(res)) == 0,
    "Expected '%s', got '%s'", pr_netaddr_get_ipstr(addr),
    pr_netaddr_get_ipstr(res));

  /* ...and where the network protocol does not match that of the address. */

  msg = "(||::1|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle network protocol mismatch");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

  msg = "(|2|1.2.3.4|5)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle network protocol mismatch");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

#ifdef PR_USE_IPV6
  addr = pr_netaddr_get_addr(p, "::1", NULL);
  fail_unless(addr != NULL, "Failed to get address for ::1: %s",
    strerror(errno));

  msg = "(|2|1.2.3.4|5)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle network protocol mismatch");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

  msg = "(|1|::1|5)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle network protocol mismatch");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

  msg = "(|2|::1|5)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle network protocol mismatch");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

  msg = "(|2|::1|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));

  msg = "(|2|::1|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, "ALL");
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));

  msg = "(||::1|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, "2");
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));

  msg = "(||::1|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));

  msg = "(|||5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res != NULL, "Failed to handle formatted message '%s': %s", msg,
    strerror(errno));
  fail_unless(
    strcmp(pr_netaddr_get_ipstr(addr), pr_netaddr_get_ipstr(res)) == 0,
    "Expected '%s', got '%s'", pr_netaddr_get_ipstr(addr),
    pr_netaddr_get_ipstr(res));

  msg = "(||1.2.3.4|5|)";
  res = proxy_ftp_msg_parse_ext_addr(p, msg, addr, PR_CMD_EPSV_ID, NULL);
  fail_unless(res == NULL, "Failed to handle network protocol mismatch");
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);
#endif /* PR_USE_IPV6 */
}
Esempio n. 2
0
const pr_netaddr_t *proxy_ftp_xfer_prepare_passive(int policy_id, cmd_rec *cmd,
    const char *error_code, struct proxy_session *proxy_sess, int flags) {
  int res, xerrno = 0;
  cmd_rec *pasv_cmd;
  const pr_netaddr_t *remote_addr = NULL;
  pr_response_t *resp;
  unsigned int resp_nlines = 0;
  unsigned short remote_port;
  char *passive_cmd, *passive_respcode = NULL;

  if (cmd == NULL ||
      error_code == NULL ||
      proxy_sess == NULL ||
      proxy_sess->backend_ctrl_conn == NULL) {
    errno = EINVAL;
    return NULL;
  }

  /* Whether we send a PASV (and expect 227) or an EPSV (and expect 229)
   * need to depend on the policy_id.
   */
  switch (policy_id) {
    case PR_CMD_PASV_ID:
      passive_cmd = C_PASV;
      break;

    case PR_CMD_EPSV_ID:
      /* If the remote host does not mention EPSV in its features, fall back
       * to using PASV.
       */
      passive_cmd = C_EPSV;
      if (pr_table_get(proxy_sess->backend_features, C_EPSV, NULL) == NULL) {
        pr_trace_msg(trace_channel, 19,
          "EPSV not supported by backend server (via FEAT), using PASV");
        if (proxy_sess->dataxfer_policy == PR_CMD_EPSV_ID) {
          proxy_sess->dataxfer_policy = PR_CMD_PASV_ID;
        }

        passive_cmd = C_PASV;
        policy_id = PR_CMD_PASV_ID;
      }
      break;

    default:
      /* In this case, the cmd we were given is the one we should send to
       * the backend server -- but only if it is either EPSV or PASV.
       */
      if (pr_cmd_cmp(cmd, PR_CMD_EPSV_ID) != 0 &&
          pr_cmd_cmp(cmd, PR_CMD_PASV_ID) != 0) {
        pr_trace_msg(trace_channel, 9,
          "illegal FTP passive transfer command '%s'", (char *) cmd->argv[0]);
        errno = EINVAL;
        return NULL;
      }

      passive_cmd = cmd->argv[0];

      if (pr_cmd_cmp(cmd, PR_CMD_EPSV_ID) == 0) {
        /* If the remote host does not mention EPSV in its features, fall back
         * to using PASV.
         */
        if (pr_table_get(proxy_sess->backend_features, C_EPSV, NULL) == NULL) {
          pr_trace_msg(trace_channel, 19,
            "EPSV not supported by backend server (via FEAT), using PASV");
          if (proxy_sess->dataxfer_policy == PR_CMD_EPSV_ID) {
            proxy_sess->dataxfer_policy = PR_CMD_PASV_ID;
          }

          passive_cmd = C_PASV;
          policy_id = PR_CMD_PASV_ID;
        }
      }

      break;
  }

  pasv_cmd = pr_cmd_alloc(cmd->tmp_pool, 1, passive_cmd);

  switch (pr_cmd_get_id(pasv_cmd->argv[0])) {
    case PR_CMD_PASV_ID:
      passive_respcode = R_227;
      break;

    case PR_CMD_EPSV_ID:
      passive_respcode = R_229;
      break;
  } 

  res = proxy_ftp_ctrl_send_cmd(cmd->tmp_pool, proxy_sess->backend_ctrl_conn,
    pasv_cmd);
  if (res < 0) {
    xerrno = errno;
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "error sending %s to backend: %s", (char *) pasv_cmd->argv[0],
      strerror(xerrno));

    pr_response_add_err(error_code, "%s: %s", (char *) cmd->argv[0],
      strerror(xerrno));
    pr_response_flush(&resp_err_list);

    errno = xerrno;
    return NULL;
  }

  resp = proxy_ftp_ctrl_recv_resp(cmd->tmp_pool, proxy_sess->backend_ctrl_conn,
    &resp_nlines, flags);
  if (resp == NULL) {
    xerrno = errno;
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "error receiving %s response from backend: %s",
      (char *) pasv_cmd->argv[0], strerror(xerrno));

    pr_response_add_err(error_code, "%s: %s", (char *) cmd->argv[0],
      strerror(xerrno));
    pr_response_flush(&resp_err_list);

    errno = xerrno;
    return NULL;
  }

  /* We specifically expect a 227 or 229 response code here; anything else is
   * an error.  Right?
   */
  if (strncmp(resp->num, passive_respcode, 4) != 0) {
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "received response code %s, but expected %s for %s command", resp->num,
      passive_respcode, (char *) pasv_cmd->argv[0]);

    if (policy_id == PR_CMD_EPSV_ID) {
      /* If using EPSV failed, try again using PASV, and switch the
       * DataTransferPolicy (if EPSV) to be PASV, for future attempts.
       */

      if (proxy_sess->dataxfer_policy == PR_CMD_EPSV_ID) {
        pr_trace_msg(trace_channel, 15,
          "falling back from EPSV to PASV DataTransferPolicy");
        proxy_sess->dataxfer_policy = PR_CMD_PASV_ID;
      }

      return proxy_ftp_xfer_prepare_passive(PR_CMD_PASV_ID, cmd,
        error_code, proxy_sess, flags);
    }

    res = proxy_ftp_ctrl_send_resp(cmd->tmp_pool,
      proxy_sess->frontend_ctrl_conn, resp, resp_nlines);

    errno = EPERM;
    return NULL;
  }

  switch (pr_cmd_get_id(pasv_cmd->argv[0])) {
    case PR_CMD_PASV_ID:
      remote_addr = proxy_ftp_msg_parse_addr(cmd->tmp_pool, resp->msg,
        pr_netaddr_get_family(session.c->local_addr));
      break;

    case PR_CMD_EPSV_ID:
      remote_addr = proxy_ftp_msg_parse_ext_addr(cmd->tmp_pool, resp->msg,
        session.c->remote_addr, PR_CMD_EPSV_ID, NULL);
      break;
  }

  if (remote_addr == NULL) {
    xerrno = errno;

    pr_trace_msg(trace_channel, 2, "error parsing %s response '%s': %s",
      (char *) pasv_cmd->argv[0], resp->msg, strerror(xerrno));

    xerrno = EPERM;
    pr_response_add_err(error_code, "%s: %s", (char *) cmd->argv[0],
      strerror(xerrno));
    pr_response_flush(&resp_err_list);

    errno = xerrno;
    return NULL;
  }

  remote_port = ntohs(pr_netaddr_get_port(remote_addr));

  /* Make sure that the given address matches the address to which we
   * originally connected.
   */

  if (pr_netaddr_cmp(remote_addr,
      proxy_sess->backend_ctrl_conn->remote_addr) != 0) {
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "Refused %s address %s (address mismatch with %s)",
      (char *) pasv_cmd->argv[0], pr_netaddr_get_ipstr(remote_addr),
      pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr));
    xerrno = EPERM;

    pr_response_add_err(error_code, "%s: %s", (char *) cmd->argv[0],
      strerror(xerrno));
    pr_response_flush(&resp_err_list);

    errno = xerrno;
    return NULL;
  }

  if (remote_port < 1024) {
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "Refused %s port %hu (below 1024)",
      (char *) pasv_cmd->argv[0], remote_port);
    xerrno = EPERM;

    pr_response_add_err(error_code, "%s: %s", (char *) cmd->argv[0],
      strerror(xerrno));
    pr_response_flush(&resp_err_list);

    errno = xerrno;
    return NULL;
  }

  return remote_addr;
}