Example #1
0
File: cmd.c Project: Nubisa/JXPanel
END_TEST

START_TEST (cmd_cmp_test) {
  cmd_rec *cmd;
  int res;

  res = pr_cmd_cmp(NULL, 1);
  fail_unless(res == -1, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL"); 

  cmd = pr_cmd_alloc(p, 1, "foo");
  res = pr_cmd_cmp(cmd, 0);
  fail_unless(res == -1, "Failed to handle bad ID argument");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL"); 

  res = pr_cmd_cmp(cmd, 1);
  fail_unless(res == 1, "Failed to handle empty cmd_rec argument");

  cmd = pr_cmd_alloc(p, 1, C_RETR);
  res = pr_cmd_cmp(cmd, PR_CMD_ACCT_ID);
  fail_unless(res > 0, "Unexpected comparison result: %d", res);

  res = pr_cmd_cmp(cmd, PR_CMD_STOR_ID);
  fail_unless(res < 0, "Unexpected comparison result: %d", res);

  res = pr_cmd_cmp(cmd, PR_CMD_RETR_ID);
  fail_unless(res == 0, "Unexpected comparison result: %d", res);
}
Example #2
0
File: cmd.c Project: Nubisa/JXPanel
END_TEST

START_TEST (cmd_strcmp_test) {
  cmd_rec *cmd;
  int res;

  res = pr_cmd_strcmp(NULL, NULL);
  fail_unless(res == -1, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  mark_point();
  cmd = pr_cmd_alloc(p, 0);
  res = pr_cmd_strcmp(cmd, "a");
  fail_unless(res == 1, "Failed to handle empty cmd_rec");

  mark_point();
  cmd = pr_cmd_alloc(p, 1, C_RETR);
  res = pr_cmd_strcmp(cmd, "a");
  fail_unless(res > 0, "Unexpected comparison result: %d", res);

  mark_point();
  cmd->cmd_id = 0;
  res = pr_cmd_strcmp(cmd, "S");
  fail_unless(res > 0, "Unexpected comparison result: %d", res);

  mark_point();
  cmd->cmd_id = 0;
  res = pr_cmd_strcmp(cmd, C_RETR);
  fail_unless(res == 0, "Unexpected comparison result: %d", res);
}
Example #3
0
END_TEST

START_TEST (cmd_is_ssh2_test) {
  int res;
  cmd_rec *cmd;

  res = pr_cmd_is_ssh2(NULL);
  fail_unless(res < 0, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  mark_point();
  cmd = pr_cmd_alloc(p, 1, C_SYST);
  cmd->argv[0] = NULL;
  res = pr_cmd_is_ssh2(cmd);
  fail_unless(res < 0, "Failed to handle null name");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  mark_point();
  cmd->argv[0] = C_SYST;
  res = pr_cmd_is_ssh2(cmd);
  fail_unless(res == FALSE, "Expected FALSE (%d), got %d", FALSE, res);

  mark_point();
  cmd = pr_cmd_alloc(p, 1, "SSH-2.0-OpenSSH_5.6p1");
  res = pr_cmd_is_ssh2(cmd);
  fail_unless(res == TRUE, "Expected TRUE (%d), got %d", TRUE, res);

  mark_point();
  cmd = pr_cmd_alloc(p, 1, "SSH-1.99-JSCH");
  res = pr_cmd_is_ssh2(cmd);
  fail_unless(res == TRUE, "Expected TRUE (%d), got %d", TRUE, res);
}
Example #4
0
END_TEST

START_TEST (module_create_ret_test) {
    cmd_rec *cmd;
    modret_t *mr;
    char *numeric, *msg;

    mr = mod_create_ret(NULL, 0, NULL, NULL);
    fail_unless(mr == NULL, "Failed to handle null arguments");
    fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
                strerror(errno), errno);

    cmd = pr_cmd_alloc(p, 1, "testsuite");
    mr = mod_create_ret(cmd, 1, NULL, NULL);
    fail_unless(mr != NULL, "Failed to create modret: %s", strerror(errno));
    fail_unless(mr->mr_error == 1, "Expected 1, got %d", mr->mr_error);
    fail_unless(mr->mr_numeric == NULL, "Expected null, got '%s'",
                mr->mr_numeric);
    fail_unless(mr->mr_message == NULL, "Expected null, got '%s'",
                mr->mr_message);

    numeric = "foo";
    msg = "bar";
    mr = mod_create_ret(cmd, 1, numeric, msg);
    fail_unless(mr != NULL, "Failed to create modret: %s", strerror(errno));
    fail_unless(mr->mr_error == 1, "Expected 1, got %d", mr->mr_error);
    fail_unless(mr->mr_numeric != NULL, "Expected '%s', got null");
    fail_unless(strcmp(mr->mr_numeric, numeric) == 0,
                "Expected '%s', got '%s'", numeric, mr->mr_numeric);
    fail_unless(mr->mr_message != NULL, "Expected '%s', got null");
    fail_unless(strcmp(mr->mr_message, msg) == 0,
                "Expected '%s', got '%s'", msg, mr->mr_message);
}
Example #5
0
static int read_service_req(struct ssh2_packet *pkt, char **service) {
  unsigned char *buf;
  char *service_name;
  uint32_t buflen;
  cmd_rec *cmd;

  buf = pkt->payload;
  buflen = pkt->payload_len;

  service_name = sftp_msg_read_string(pkt->pool, &buf, &buflen);
  pr_trace_msg(trace_channel, 10, "'%s' service requested", service_name);

  cmd = pr_cmd_alloc(pkt->pool, 1, pstrdup(pkt->pool, "SERVICE_REQUEST"));
  cmd->arg = service_name;
  cmd->cmd_class = CL_MISC|CL_SSH;

  if (strncmp(service_name, "ssh-userauth", 13) == 0 ||
      strncmp(service_name, "ssh-connection", 14) == 0) {
    if (service)
      *service = pstrdup(service_pool, service_name);

    pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
    return 0;
  }

  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
    "client requested unsupported '%s' service", service_name);

  pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
  return -1;
}
Example #6
0
END_TEST

START_TEST (cmd_get_errno_test) {
  int res, *xerrno = NULL;
  cmd_rec *cmd = NULL;

  res = pr_cmd_get_errno(NULL);
  fail_unless(res == -1, "Failed to handle null cmd_rec");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  cmd = pr_cmd_alloc(p, 1, "foo");
  res = pr_cmd_get_errno(cmd);
  fail_unless(res == 0, "Expected errno 0, got %d", res);

  (void) pr_table_remove(cmd->notes, "errno", NULL);
  res = pr_cmd_get_errno(cmd);
  fail_unless(res < 0, "Failed to handle missing 'errno' note");
  fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
    strerror(errno), errno);

  xerrno = pcalloc(cmd->pool, sizeof(int));
  (void) pr_table_add(cmd->notes, "errno", xerrno, sizeof(int));

  res = pr_cmd_set_errno(NULL, ENOENT);
  fail_unless(res < 0, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  res = pr_cmd_set_errno(cmd, ENOENT);
  fail_unless(res == 0, "Failed to stash errno ENOENT: %s", strerror(errno));

  res = pr_cmd_get_errno(cmd);
  fail_unless(res == ENOENT, "Expected errno ENOENT, got %s (%d)",
    strerror(res), res);
}
Example #7
0
END_TEST

START_TEST (module_create_error_test) {
    cmd_rec *cmd;
    modret_t *mr;

    mr = mod_create_error(NULL, 0);
    fail_unless(mr == NULL, "Failed to handle null arguments");
    fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
                strerror(errno), errno);

    cmd = pr_cmd_alloc(p, 1, "testsuite");
    mr = mod_create_error(cmd, 1);
    fail_unless(mr != NULL, "Failed to create modret: %s", strerror(errno));
    fail_unless(mr->mr_error == 1, "Expected 1, got %d", mr->mr_error);
}
Example #8
0
END_TEST

START_TEST (module_create_data_test) {
    cmd_rec *cmd;
    modret_t *mr;
    int data = 1;

    mr = mod_create_data(NULL, NULL);
    fail_unless(mr == NULL, "Failed to handle null arguments");
    fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
                strerror(errno), errno);

    cmd = pr_cmd_alloc(p, 1, "testsuite");
    mr = mod_create_data(cmd, &data);
    fail_unless(mr != NULL, "Failed to create modret: %s", strerror(errno));
    fail_unless(mr->data == &data, "Expected %p, got %p", &data, mr->data);
}
Example #9
0
END_TEST

START_TEST (response_pool_bug3711_test) {
  int res;
  cmd_rec *cmd;
  pool *resp_pool, *cmd_pool;
  char *err_code = R_450, *err_msg = "Busy";

  resp_pool = make_sub_pool(p);
  cmd_pool = make_sub_pool(p);

  cmd = pr_cmd_alloc(cmd_pool, 1, "foo");

  pr_response_set_pool(cmd->pool);
  pr_response_add_err(err_code, "%s", err_msg);

  /* We expect segfaults here, so use the mark_point() function to get
   * more accurate reporting of the problematic line of code in the
   * error logs.
   */
  mark_point();

  /* We explicitly do NOT reset the Response API pool here, to emulate the
   * behavior of Bug#3711.
   *
   * In the future, we could address this by proving a Pool API function
   * that e.g. the Response API could use, to check whether the given
   * pool is still a valid pool.  To do this, the Pool API would keep a
   * list of allocated pools, which would then be scanned.  In practice such
   * a list is maintained, albeit in a tree form.  And there is tracking
   * of the root trees for pools; permanent_pool is not the only root pool
   * which can be created/used.
   */
  destroy_pool(cmd_pool);

  mark_point();
  pr_response_add_err(err_code, "%s", err_msg);

  mark_point();
  pr_response_add_err(err_code, "%s", err_msg);

  mark_point();
  pr_response_add_err(err_code, "%s", err_msg);
}
Example #10
0
int proxy_ftp_sess_send_host(pool *p, struct proxy_session *proxy_sess) {
    pool *tmp_pool;
    int xerrno = 0;
    cmd_rec *cmd;
    pr_response_t *resp;
    unsigned int resp_nlines = 0;
    const char *host;

    if (pr_table_get(proxy_sess->backend_features, C_HOST, NULL) == NULL) {
        pr_trace_msg(trace_channel, 9,
                     "HOST not supported by backend server, ignoring");
        return 0;
    }

    tmp_pool = make_sub_pool(p);

    host = proxy_conn_get_host(proxy_sess->dst_pconn);
    cmd = pr_cmd_alloc(tmp_pool, 2, C_HOST, host);
    cmd->arg = pstrdup(tmp_pool, host);

    resp = send_recv(tmp_pool, proxy_sess->backend_ctrl_conn, cmd, &resp_nlines);
    if (resp == NULL) {
        xerrno = errno;
        destroy_pool(tmp_pool);
        errno = xerrno;
        return -1;
    }

    if (resp->num[0] != '2') {
        pr_trace_msg(trace_channel, 4,
                     "received unexpected %s response code %s from backend",
                     (char *) cmd->argv[0], resp->num);
        destroy_pool(tmp_pool);
        errno = EPERM;
        return -1;
    }

    destroy_pool(tmp_pool);
    return 0;
}
Example #11
0
END_TEST

START_TEST (cmd_set_name_test) {
  int res;
  cmd_rec *cmd;
  const char *name;

  res = pr_cmd_set_name(NULL, NULL);
  fail_unless(res < 0, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  cmd = pr_cmd_alloc(p, 1, "foo");
  res = pr_cmd_set_name(cmd, NULL);
  fail_unless(res < 0, "Failed to handle null name");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  name = "bar";
  res = pr_cmd_set_name(cmd, name);
  fail_unless(res == 0, "Failed to command name to '%s': %s", name,
    strerror(errno));
}
Example #12
0
File: cmd.c Project: Nubisa/JXPanel
END_TEST

START_TEST (cmd_get_displayable_str_test) {
  char *ok, *res = NULL;
  cmd_rec *cmd = NULL;
  size_t len = 0;

  res = pr_cmd_get_displayable_str(NULL, NULL);
  fail_unless(res == NULL, "Failed to handle null cmd_rec");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  cmd = pr_cmd_alloc(p, 1, "foo");
  res = pr_cmd_get_displayable_str(cmd, NULL);

  ok = "foo";
  fail_if(res == NULL, "Expected string, got null");
  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);

  mark_point();
  cmd->argc = 0;
  res = pr_cmd_get_displayable_str(cmd, NULL);

  fail_if(res == NULL, "Expected string, got null");

  /* Note: We still expect the PREVIOUS ok value, since
   * pr_cmd_get_displayable_str() should cache the constructed string,
   * rather than creating it anew.
   */
  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);

  mark_point();
  pr_cmd_clear_cache(cmd);
  res = pr_cmd_get_displayable_str(cmd, NULL);

  ok = "";
  fail_if(res == NULL, "Expected string, got null");
  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);

  mark_point();
  cmd = pr_cmd_alloc(p, 1, "bar");
  cmd->arg = NULL;
  res = pr_cmd_get_displayable_str(cmd, NULL);

  ok = "bar";
  fail_if(res == NULL, "Expected string, got null");
  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);

  mark_point();
  cmd = pr_cmd_alloc(p, 1, "baz");
  cmd->argv[0] = NULL;
  cmd->arg = pstrdup(p, "baz");
  res = pr_cmd_get_displayable_str(cmd, NULL);

  /* cmd->argv[0] is the command name; without that, it does not matter
   * what cmd->arg is.  Hence why if cmd->argv[0] is null, we expect the
   * empty string.
   */
  ok = "";
  fail_if(res == NULL, "Expected string, got null");
  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);

  mark_point();
  cmd = pr_cmd_alloc(p, 3, "foo", "bar", "baz");
  cmd->arg = NULL;
  res = pr_cmd_get_displayable_str(cmd, NULL);
  
  /* cmd->argv[0] is the command name; without that, it does not matter
   * what cmd->arg is.  Hence why if cmd->argv[0] is null, we expect the
   * empty string.
   */
  ok = "foo bar baz";
  fail_if(res == NULL, "Expected string, got null");
  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);

  /* Make sure we can handle cases where cmd_rec->argv has been tampered
   * with.
   */
  mark_point();
  cmd = pr_cmd_alloc(p, 3, "foo", "bar", "baz");
  cmd->argv[0] = NULL;
  res = pr_cmd_get_displayable_str(cmd, NULL);

  ok = " bar baz";
  fail_if(res == NULL, "Expected string, got null");
  fail_unless(strcmp(res, ok) == 0, "Expected '%s', got '%s'", ok, res);
}
Example #13
0
int proxy_ftp_sess_send_auth_tls(pool *p, struct proxy_session *proxy_sess) {
  int uri_tls, use_tls, xerrno;
  char *auth_feat;
  array_header *auth_feats = NULL;
  pool *tmp_pool;
  cmd_rec *cmd;
  pr_response_t *resp;
  unsigned int resp_nlines = 0;

  use_tls = proxy_tls_use_tls();
  if (use_tls == PROXY_TLS_ENGINE_OFF) {
    pr_trace_msg(trace_channel, 19,
      "TLS support not enabled/desired, skipping");
    return 0;
  }

  /* Check for any per-URI scheme-based TLS requirements. */
  uri_tls = proxy_conn_get_tls(proxy_sess->dst_pconn);

  auth_feat = pr_table_get(proxy_sess->backend_features, C_AUTH, NULL);
  if (auth_feat == NULL) {
    /* Backend server does not indicate that it supports AUTH via FEAT. */

    /* If TLS is required, then fail now. */
    if (uri_tls == PROXY_TLS_ENGINE_ON ||
        use_tls == PROXY_TLS_ENGINE_ON) {
      const char *ip_str;

      ip_str = pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr);

      if (uri_tls == PROXY_TLS_ENGINE_ON) {
        (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
          "backend server %s does not support AUTH TLS (see FEAT response) but "
          "URI '%.100s' requires TLS, failing connection", ip_str,
          proxy_conn_get_uri(proxy_sess->dst_pconn));

      } else if (use_tls == PROXY_TLS_ENGINE_ON) {
        (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
          "backend server %s does not support AUTH TLS (see FEAT response) but "
          "ProxyTLSEngine requires TLS, failing connection", ip_str);
      }

      errno = EPERM;
      return -1;
    }

    /* Tell the Proxy NetIO API to NOT try to use our TLS NetIO. */
    proxy_netio_use(PR_NETIO_STRM_CTRL, NULL);

    pr_trace_msg(trace_channel, 9,
      "backend server does not support AUTH TLS (via FEAT), skipping");
    return 0;
  }

  tmp_pool = make_sub_pool(p);

  /* Note: the FEAT response against IIS servers shows e.g.:
   *
   * 211-Extended features supported:
   *  LANG EN*
   *  UTF8
   *  AUTH TLS;TLS-C;SSL;TLS-P;
   *  PBSZ
   *  PROT C;P;
   *  CCC
   *  HOST
   *  SIZE
   *  MDTM
   *  REST STREAM
   * 211 END
   *
   * Note how the AUTH and PROT values are not exactly as specified
   * in RFC 4217.  This means we'll need to deal with as is.  There will
   * be other servers with other FEAT response formats, too.
   */
  if (parse_feat(tmp_pool, auth_feat, &auth_feats) > 0) {
    register unsigned int i;

    pr_trace_msg(trace_channel, 9, "parsed FEAT value '%s' into %d values",
      auth_feat, auth_feats->nelts);
    for (i = 0; i < auth_feats->nelts; i++) {
      char *val;

      val = ((char **) auth_feats->elts)[i];
      pr_trace_msg(trace_channel, 9, " %s", val);
    }
  }

  cmd = pr_cmd_alloc(tmp_pool, 2, C_AUTH, "TLS");
  cmd->arg = pstrdup(tmp_pool, "TLS");

  resp = send_recv(tmp_pool, proxy_sess->backend_ctrl_conn, cmd, &resp_nlines);
  if (resp == NULL) {
    xerrno = errno;

    proxy_netio_use(PR_NETIO_STRM_CTRL, NULL);
    destroy_pool(tmp_pool);
    errno = xerrno;
    return -1;
  }

  if (resp->num[0] != '2') {
    pr_trace_msg(trace_channel, 4,
      "received unexpected %s response code %s from backend",
      (char *) cmd->argv[0], resp->num);

    proxy_netio_use(PR_NETIO_STRM_CTRL, NULL);
    destroy_pool(tmp_pool);
    errno = EPERM;
    return -1;
  }

  destroy_pool(tmp_pool);
  return 0;
}
Example #14
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;
}
Example #15
0
int sftp_kbdint_recv_response(pool *p, unsigned int expected_count,
    unsigned int *rcvd_count, const char ***responses) {
  register unsigned int i;
  unsigned char *buf;
  cmd_rec *cmd;
  array_header *list;
  uint32_t buflen, resp_count;
  struct ssh2_packet *pkt;
  char mesg_type;
  int res;

  if (p == NULL ||
      rcvd_count == NULL ||
      responses == NULL) {
    errno = EINVAL;
    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;
  }

  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)";

  pr_trace_msg(trace_channel, 9,
    "reading USER_AUTH_INFO_RESP message from client");

  buf = pkt->payload;
  buflen = pkt->payload_len;

  resp_count = sftp_msg_read_int(pkt->pool, &buf, &buflen);

  /* Ensure that the number of responses sent by the client is the same
   * as the number of challenges sent, lest a malicious client attempt to
   * trick us into allocating too much memory (Bug#3973).
   */
  if (resp_count != expected_count) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "sent %lu %s, but received %lu %s", (unsigned long) expected_count,
      expected_count != 1 ? "challenges" : "challenge",
      (unsigned long) resp_count, resp_count != 1 ? "responses" : "response");
    destroy_pool(pkt->pool);
    errno = EPERM;
    return -1;
  }

  if (resp_count > SFTP_KBDINT_MAX_RESPONSES) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "received too many responses (%lu > max %lu), rejecting",
      (unsigned long) resp_count, (unsigned long) SFTP_KBDINT_MAX_RESPONSES);
    destroy_pool(pkt->pool);
    errno = EPERM;
    return -1;
  }

  list = make_array(p, resp_count, sizeof(char *));
  for (i = 0; i < resp_count; i++) {
    char *resp;

    resp = sftp_msg_read_string(pkt->pool, &buf, &buflen);
    *((char **) push_array(list)) = pstrdup(p, sftp_utf8_decode_str(p, resp));
  }

  *rcvd_count = (unsigned int) resp_count;
  *responses = ((const char **) list->elts);
  return 0;
}
Example #16
0
int proxy_ftp_sess_get_feat(pool *p, struct proxy_session *proxy_sess) {
    pool *tmp_pool;
    int res, xerrno = 0;
    cmd_rec *cmd;
    pr_response_t *resp;
    unsigned int resp_nlines = 0;
    char *feats, *token;
    size_t token_len = 0;

    tmp_pool = make_sub_pool(p);

    cmd = pr_cmd_alloc(tmp_pool, 1, C_FEAT);
    res = proxy_ftp_ctrl_send_cmd(tmp_pool, proxy_sess->backend_ctrl_conn, cmd);
    if (res < 0) {
        xerrno = errno;

        pr_trace_msg(trace_channel, 4,
                     "error sending %s to backend: %s", (char *) cmd->argv[0],
                     strerror(xerrno));
        destroy_pool(tmp_pool);

        errno = xerrno;
        return -1;
    }

    resp = proxy_ftp_ctrl_recv_resp(tmp_pool, proxy_sess->backend_ctrl_conn,
                                    &resp_nlines);
    if (resp == NULL) {
        xerrno = errno;

        pr_trace_msg(trace_channel, 4,
                     "error receiving %s response from backend: %s", (char *) cmd->argv[0],
                     strerror(xerrno));
        destroy_pool(tmp_pool);

        errno = xerrno;
        return -1;
    }

    if (resp->num[0] != '2') {
        pr_trace_msg(trace_channel, 4,
                     "received unexpected %s response code %s from backend",
                     (char *) cmd->argv[0], resp->num);

        /* Note: If the UseProxyProtocol ProxyOption is enabled, AND if the
         * response message mentions a "PROXY" command, we might read an
         * error response here that is NOT actually for the FEAT command we just
         * sent.
         *
         * A backend FTP server which does not understand the PROXY protocol
         * will treat it as a normal FTP command, and respond.  And that will
         * put us, the client, out of lockstep with the server, for how do we know
         * that we need to read that error response FIRST, then send another
         * command?
         */

        destroy_pool(tmp_pool);
        errno = EPERM;
        return -1;
    }

    proxy_sess->backend_features = pr_table_nalloc(p, 0, 4);

    feats = resp->msg;
    token = pr_str_get_token2(&feats, (char *) feat_crlf, &token_len);
    while (token != NULL) {
        pr_signals_handle();

        if (token_len > 0) {
            /* The FEAT response lines in which we are interested all start with
             * a single space, per RFC spec.  Ignore any other lines.
             */
            if (token[0] == ' ') {
                char *key, *val, *ptr;

                /* Find the next space in the string, to delimit our key/value pairs. */
                ptr = strchr(token + 1, ' ');
                if (ptr != NULL) {
                    key = pstrndup(p, token + 1, ptr - token - 1);
                    val = pstrdup(p, ptr + 1);

                } else {
                    key = pstrdup(p, token + 1);
                    val = pstrdup(p, "");
                }

                pr_table_add(proxy_sess->backend_features, key, val, 0);
            }
        }

        feats = token + token_len + 1;
        token = pr_str_get_token2(&feats, (char *) feat_crlf, &token_len);
    }

    destroy_pool(tmp_pool);
    return 0;
}
Example #17
0
int proxy_ftp_sess_send_pbsz_prot(pool *p, struct proxy_session *proxy_sess) {
    int use_tls;

    use_tls = proxy_tls_use_tls();
    if (use_tls == PROXY_TLS_ENGINE_OFF) {
        pr_trace_msg(trace_channel, 19,
                     "TLS support not enabled/desired, skipping");
        return 0;
    }

    if (pr_table_get(proxy_sess->backend_features, C_PBSZ, NULL) != NULL) {
        int xerrno;
        pool *tmp_pool;
        cmd_rec *cmd;
        pr_response_t *resp;
        unsigned int resp_nlines = 0;

        tmp_pool = make_sub_pool(p);

        cmd = pr_cmd_alloc(tmp_pool, 2, C_PBSZ, "0");
        cmd->arg = pstrdup(tmp_pool, "0");

        resp = send_recv(tmp_pool, proxy_sess->backend_ctrl_conn, cmd,
                         &resp_nlines);
        if (resp == NULL) {
            xerrno = errno;
            destroy_pool(tmp_pool);
            errno = xerrno;
            return -1;
        }

        if (resp->num[0] != '2') {
            pr_trace_msg(trace_channel, 4,
                         "received unexpected %s response code %s from backend",
                         (char *) cmd->argv[0], resp->num);
            destroy_pool(tmp_pool);
            errno = EPERM;
            return -1;
        }

        destroy_pool(tmp_pool);
    }

    if (pr_table_get(proxy_sess->backend_features, C_PROT, NULL) != NULL) {
        int xerrno;
        pool *tmp_pool;
        cmd_rec *cmd;
        pr_response_t *resp;
        unsigned int resp_nlines = 0;

        tmp_pool = make_sub_pool(p);

        cmd = pr_cmd_alloc(tmp_pool, 2, C_PROT, "P");
        cmd->arg = pstrdup(tmp_pool, "P");

        resp = send_recv(tmp_pool, proxy_sess->backend_ctrl_conn, cmd,
                         &resp_nlines);
        if (resp == NULL) {
            xerrno = errno;
            destroy_pool(tmp_pool);
            errno = xerrno;
            return -1;
        }

        if (resp->num[0] != '2') {
            pr_trace_msg(trace_channel, 4,
                         "received unexpected %s response code %s from backend",
                         (char *) cmd->argv[0], resp->num);
            destroy_pool(tmp_pool);
            errno = EPERM;
            return -1;
        }

        destroy_pool(tmp_pool);
    }

    return 0;
}
Example #18
0
int proxy_ftp_sess_send_auth_tls(pool *p, struct proxy_session *proxy_sess) {
    int uri_tls, use_tls, xerrno;
    char *auth_feat;
    array_header *auth_feats = NULL;
    pool *tmp_pool;
    cmd_rec *cmd;
    pr_response_t *resp;
    unsigned int resp_nlines = 0;

    use_tls = proxy_tls_use_tls();
    if (use_tls == PROXY_TLS_ENGINE_OFF) {
        pr_trace_msg(trace_channel, 19,
                     "TLS support not enabled/desired, skipping");
        return 0;
    }

    /* Check for any per-URI scheme-based TLS requirements. */
    uri_tls = proxy_conn_get_tls(proxy_sess->dst_pconn);

    auth_feat = pr_table_get(proxy_sess->backend_features, C_AUTH, NULL);
    if (auth_feat == NULL) {
        /* Backend server does not indicate that it supports AUTH via FEAT.
         *
         * Even though this is the case, we will still try to send the AUTH
         * command.  A malicious attacker could be modifying the plaintext
         * FEAT listing, to make us think that TLS is not supported, and thus
         * prevent us from encrypting the session (a la "SSL stripping").
         */

        /* If TLS is required, then complain loudly.  */
        if (uri_tls == PROXY_TLS_ENGINE_ON ||
                use_tls == PROXY_TLS_ENGINE_ON) {
            const char *ip_str;

            ip_str = pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr);

            if (uri_tls == PROXY_TLS_ENGINE_ON) {
                (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
                                        "backend server %s does not support AUTH TLS (see FEAT response) but "
                                        "URI '%.100s' requires TLS, attempting anyway", ip_str,
                                        proxy_conn_get_uri(proxy_sess->dst_pconn));

            } else if (use_tls == PROXY_TLS_ENGINE_ON) {
                (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
                                        "backend server %s does not support AUTH TLS (see FEAT response) but "
                                        "ProxyTLSEngine requires TLS, attempting anyway", ip_str);
            }
        }

        pr_trace_msg(trace_channel, 9,
                     "backend server does not support AUTH TLS (via FEAT)");
    }

    tmp_pool = make_sub_pool(p);

    /* Note: the FEAT response against IIS servers shows e.g.:
     *
     * 211-Extended features supported:
     *  LANG EN*
     *  UTF8
     *  AUTH TLS;TLS-C;SSL;TLS-P;
     *  PBSZ
     *  PROT C;P;
     *  CCC
     *  HOST
     *  SIZE
     *  MDTM
     *  REST STREAM
     * 211 END
     *
     * Note how the AUTH and PROT values are not exactly as specified
     * in RFC 4217.  This means we'll need to deal with it as is.  There will
     * be other servers with other FEAT response formats, too.
     */
    if (parse_feat(tmp_pool, auth_feat, &auth_feats) > 0) {
        register unsigned int i;

        pr_trace_msg(trace_channel, 9, "parsed FEAT value '%s' into %d values",
                     auth_feat, auth_feats->nelts);
        for (i = 0; i < auth_feats->nelts; i++) {
            char *val;

            val = ((char **) auth_feats->elts)[i];
            pr_trace_msg(trace_channel, 9, " %s", val);
        }
    }

    /* XXX How should we interoperate with servers that support/want the
     * older formats, e.g.:
     *
     *  AUTH SSL (which automatically assumes PBSZ 0, PROT P)
     *  AUTH TLS-P (synonym for AUTH SSL)
     *  AUTH TLS-C (synonym for AUTH TLS)
     */

    cmd = pr_cmd_alloc(tmp_pool, 2, C_AUTH, "TLS");
    cmd->arg = pstrdup(tmp_pool, "TLS");

    resp = send_recv(tmp_pool, proxy_sess->backend_ctrl_conn, cmd, &resp_nlines);
    if (resp == NULL) {
        xerrno = errno;

        proxy_netio_use(PR_NETIO_STRM_CTRL, NULL);
        destroy_pool(tmp_pool);
        errno = xerrno;
        return -1;
    }

    if (resp->num[0] != '2') {
        /* XXX Some older servers might respond with a 334 response code, per
         * RFC 2228.  See, for example:
         *   http://serverfault.com/questions/640978/ftp-alter-server-response-in-transit
         */
        pr_trace_msg(trace_channel, 4,
                     "received unexpected %s response code %s from backend",
                     (char *) cmd->argv[0], resp->num);

        proxy_netio_use(PR_NETIO_STRM_CTRL, NULL);
        destroy_pool(tmp_pool);
        errno = EPERM;
        return -1;
    }

    destroy_pool(tmp_pool);
    return 0;
}
Example #19
0
int proxy_ftp_xfer_prepare_active(int policy_id, cmd_rec *cmd,
    const char *error_code, struct proxy_session *proxy_sess, int flags) {
  int backend_family, bind_family, res, xerrno = 0;
  cmd_rec *actv_cmd;
  const pr_netaddr_t *bind_addr = NULL;
  pr_response_t *resp;
  unsigned int resp_nlines = 0;
  conn_t *data_conn = NULL;
  char *active_cmd;
  const char *resp_msg = NULL;

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

  switch (policy_id) {
    case PR_CMD_PORT_ID:
      active_cmd = C_PORT;
      break;

    case PR_CMD_EPRT_ID:
      /* If the remote host does not mention EPRT in its features, fall back
       * to using PORT.
       */
      active_cmd = C_EPRT;
      if (pr_table_get(proxy_sess->backend_features, C_EPRT, NULL) == NULL) {
        pr_trace_msg(trace_channel, 19,
          "EPRT not supported by backend server (via FEAT), using PORT");
        if (proxy_sess->dataxfer_policy == PR_CMD_EPRT_ID) {
          proxy_sess->dataxfer_policy = PR_CMD_PORT_ID;
        }

        active_cmd = C_PORT;
        policy_id = PR_CMD_PORT_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 EPRT or PORT.
       */
      if (pr_cmd_cmp(cmd, PR_CMD_EPRT_ID) != 0 &&
          pr_cmd_cmp(cmd, PR_CMD_PORT_ID) != 0) {
        pr_trace_msg(trace_channel, 9,
          "illegal FTP active transfer command '%s'", (char *) cmd->argv[0]);
        errno = EINVAL;
        return -1;
      }

      active_cmd = cmd->argv[0];

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

          active_cmd = C_PORT;
          policy_id = PR_CMD_PORT_ID;
        }
      }

      break;
  }

  bind_addr = proxy_sess->src_addr;
  if (bind_addr == NULL) {
    bind_addr = session.c->local_addr;
  }

  if (pr_netaddr_is_loopback(bind_addr) == TRUE &&
      pr_netaddr_is_loopback(proxy_sess->backend_ctrl_conn->remote_addr) != TRUE) {
    const char *local_name;
    const pr_netaddr_t *local_addr;

    local_name = pr_netaddr_get_localaddr_str(cmd->pool);
    local_addr = pr_netaddr_get_addr(cmd->pool, local_name, NULL);

    if (local_addr != NULL) {
      pr_trace_msg(trace_channel, 14,
        "%s is a loopback address, using %s instead",
        pr_netaddr_get_ipstr(bind_addr), pr_netaddr_get_ipstr(local_addr));
      bind_addr = local_addr;
    }
  }

  /* Need to check the family of the bind addr against the family of the
   * backend server.
   */
  backend_family = pr_netaddr_get_family(proxy_sess->backend_ctrl_conn->remote_addr);
  bind_family = pr_netaddr_get_family(bind_addr);

  if (bind_family == backend_family) {
#ifdef PR_USE_IPV6
    if (pr_netaddr_use_ipv6()) {
      /* Make sure that the family is NOT IPv6, even though the local and
       * remote families match.  The PORT command cannot be used for IPv6
       * addresses -- but EPRT CAN be used for IPv6 addresses.
       */
      if (bind_family == AF_INET6 &&
          policy_id == PR_CMD_PORT_ID) {
        pr_netaddr_t *mapped_addr;

        mapped_addr = pr_netaddr_v6tov4(cmd->pool, bind_addr);
        if (mapped_addr != NULL) {
          pr_trace_msg(trace_channel, 9,
            "converting local IPv6 address '%s' to IPv4 address '%s' for "
            "active transfer using PORT", pr_netaddr_get_ipstr(bind_addr),
            pr_netaddr_get_ipstr(mapped_addr));
          bind_addr = mapped_addr;
        }
      }
    }
#endif /* PR_USE_IPV6 */
  } else {
    if (backend_family == AF_INET) {
      pr_netaddr_t *mapped_addr;

      /* In this scenario, the remote peer is an IPv4 (or IPv4-mapped IPv6)
       * peer, so make sure we use an IPv4 local address.
       */
      mapped_addr = pr_netaddr_v6tov4(cmd->pool, bind_addr);
      if (mapped_addr != NULL) {
        pr_trace_msg(trace_channel, 9,
          "converting local IPv6 address '%s' to IPv4 address '%s' for "
          "active transfer with IPv4 peer", pr_netaddr_get_ipstr(bind_addr),
          pr_netaddr_get_ipstr(mapped_addr));
        bind_addr = mapped_addr;
      }
    }
  }

  if (proxy_sess->backend_data_conn != NULL) {
    /* Make sure that we only have one backend data connection. */
    proxy_inet_close(session.pool, proxy_sess->backend_data_conn);
    proxy_sess->backend_data_conn = NULL;
  }

  data_conn = proxy_ftp_conn_listen(cmd->tmp_pool, bind_addr, FALSE);
  if (data_conn == NULL) {
    xerrno = errno;

    pr_response_add_err(error_code,
      _("Unable to build data connection: Internal error"));
    pr_response_flush(&resp_err_list);

    errno = xerrno;
    return -1;
  }

  proxy_sess->backend_data_conn = data_conn;

  switch (pr_cmd_get_id(active_cmd)) {
    case PR_CMD_PORT_ID:
      resp_msg = proxy_ftp_msg_fmt_addr(cmd->tmp_pool, data_conn->local_addr,
        data_conn->local_port, FALSE);
      break;

    case PR_CMD_EPRT_ID:
      resp_msg = proxy_ftp_msg_fmt_ext_addr(cmd->tmp_pool,
        data_conn->local_addr, data_conn->local_port, PR_CMD_EPRT_ID, FALSE);
      break;
  }

  actv_cmd = pr_cmd_alloc(cmd->tmp_pool, 2, active_cmd, resp_msg);
  actv_cmd->arg = (char *) resp_msg;

  pr_cmd_clear_cache(actv_cmd);

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

    proxy_inet_close(session.pool, proxy_sess->backend_data_conn);
    proxy_sess->backend_data_conn = NULL;

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

    errno = xerrno;
    return -1;
  }

  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 *) actv_cmd->argv[0], strerror(xerrno));

    proxy_inet_close(session.pool, proxy_sess->backend_data_conn);
    proxy_sess->backend_data_conn = NULL;

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

    errno = xerrno;
    return -1;
  }

  if (resp->num[0] != '2') {
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "received non-2xx response from backend for %s: %s %s",
      (char *) actv_cmd->argv[0], resp->num, resp->msg);

    proxy_inet_close(session.pool, proxy_sess->backend_data_conn);
    proxy_sess->backend_data_conn = NULL;

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

      if (proxy_sess->dataxfer_policy == PR_CMD_EPRT_ID) {
        pr_trace_msg(trace_channel, 15,
          "falling back from EPRT to PORT DataTransferPolicy");
        proxy_sess->dataxfer_policy = PR_CMD_PORT_ID;
      }

      return proxy_ftp_xfer_prepare_active(PR_CMD_PORT_ID, cmd,
        error_code, proxy_sess, flags);
    }

    pr_response_add_err(error_code, "%s", resp->msg);
    pr_response_flush(&resp_err_list);

    errno = EINVAL;
    return -1;
  }

  return 0;
}
Example #20
0
static int forward_handle_user_passthru(cmd_rec *cmd,
    struct proxy_session *proxy_sess, int *successful, int flags) {
  int res, xerrno;
  char *user = NULL;
  cmd_rec *user_cmd = NULL;
  pr_response_t *resp = NULL;
  unsigned int resp_nlines = 0;

  if (flags & PROXY_FORWARD_USER_PASSTHRU_FL_PARSE_DSTADDR) {
    struct proxy_conn *pconn = NULL;
    pr_netaddr_t *remote_addr = NULL;
    array_header *other_addrs = NULL;

    res = forward_cmd_parse_dst(cmd->tmp_pool, cmd->arg, &user, &pconn);
    if (res < 0) {
      errno = EINVAL;
      return -1;
    }

    remote_addr = proxy_conn_get_addr(pconn, &other_addrs);

    /* Ensure that the requested remote address is NOT (blatantly) ourselves,
     * i.e. the proxy itself.  This prevents easy-to-detect proxy loops.
     */
    if (pr_netaddr_cmp(remote_addr, session.c->local_addr) == 0 &&
        pr_netaddr_get_port(remote_addr) == pr_netaddr_get_port(session.c->local_addr)) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "requested destination %s#%u is local address %s#%u, rejecting",
        pr_netaddr_get_ipstr(remote_addr),
        ntohs(pr_netaddr_get_port(remote_addr)),
        pr_netaddr_get_ipstr(session.c->local_addr),
        ntohs(pr_netaddr_get_port(session.c->local_addr)));
      pr_response_send(R_530, _("Unable to connect to %s: %s"),
        proxy_conn_get_hostport(pconn), strerror(EPERM));
      return 1;
    }

    proxy_sess->dst_addr = remote_addr;
    proxy_sess->other_addrs = other_addrs;
    proxy_sess->dst_pconn = pconn;

    /* Change the command so that it no longer includes the proxy info. */
    user_cmd = pr_cmd_alloc(cmd->pool, 2, C_USER, user);
    user_cmd->arg = user;

  } else {
    user_cmd = cmd;
  }

  if (flags & PROXY_FORWARD_USER_PASSTHRU_FL_CONNECT_DSTADDR) {
    pr_response_t *banner = NULL;
    unsigned int banner_nlines = 0;

    res = forward_connect(proxy_pool, proxy_sess, &banner, &banner_nlines);
    if (res < 0) {
      xerrno = errno;

      *successful = FALSE;

      /* Send a failed USER response to our waiting frontend client, but do
       * not necessarily close the frontend connection.
       */
      resp = pcalloc(cmd->tmp_pool, sizeof(pr_response_t));
      resp->num = R_530;

      if (banner != NULL) {
        resp->msg = banner->msg;
        resp_nlines = banner_nlines;

      } else {
        resp->msg = pstrcat(cmd->tmp_pool, "Unable to connect to ",
          proxy_conn_get_hostport(proxy_sess->dst_pconn), ": ",
          strerror(xerrno), NULL);
        resp_nlines = 1;
      }

      res = proxy_ftp_ctrl_send_resp(cmd->tmp_pool,
        proxy_sess->frontend_ctrl_conn, resp, resp_nlines);
      if (res < 0) {
        xerrno = errno;

        pr_response_block(TRUE);
        errno = xerrno;
        return -1;
      }

      return 1;
    }
  }

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

    errno = xerrno;
    return -1;
  }

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

    errno = xerrno;
    return -1;
  }

  if (resp->num[0] == '2' ||
      resp->num[0] == '3') {
    *successful = TRUE;

    if (strcmp(resp->num, R_232) == 0) {
      proxy_sess_state |= PROXY_SESS_STATE_BACKEND_AUTHENTICATED;
      pr_timer_remove(PR_TIMER_LOGIN, ANY_MODULE);
    }
  }

  /* XXX TODO: Concatenate the banner from the connect with the USER response
   * message here, and send the entire kit to the frontend client, e.g.:
   * 
   *  Name (gatekeeper:you): [email protected]
   *  331-(----GATEWAY CONNECTED TO ftp.uu.net----)
   *  331-(220 ftp.uu.net FTP server (SunOS 4.1) ready. 
   *  331 Guest login ok, send ident as password.
   *  Password: ######
   *  230 Guest login ok, access restrictions apply.
   *  ftp> dir
   */

  res = proxy_ftp_ctrl_send_resp(cmd->tmp_pool, proxy_sess->frontend_ctrl_conn,
    resp, resp_nlines);
  if (res < 0) {
    xerrno = errno;

    pr_response_block(TRUE);
    errno = xerrno;
    return -1;
  }

  return 1; 
}
Example #21
0
static int copy_dir(pool *p, const char *src_dir, const char *dst_dir) {
  DIR *dh = NULL;
  struct dirent *dent = NULL;
  int res = 0;
  pool *iter_pool = NULL;

  dh = opendir(src_dir);
  if (dh == NULL) {
    pr_log_pri(PR_LOG_WARNING, MOD_COPY_VERSION
      ": error reading directory '%s': %s", src_dir, strerror(errno));
    return -1;
  }

  while ((dent = readdir(dh)) != NULL) {
    struct stat st;
    char *src_path, *dst_path;

    pr_signals_handle();

    /* Skip "." and ".." */
    if (strncmp(dent->d_name, ".", 2) == 0 ||
        strncmp(dent->d_name, "..", 3) == 0) {
      continue;
    }

    if (iter_pool != NULL) {
      destroy_pool(iter_pool);
    }

    iter_pool = pr_pool_create_sz(p, 128);
    src_path = pdircat(iter_pool, src_dir, dent->d_name, NULL);
    dst_path = pdircat(iter_pool, dst_dir, dent->d_name, NULL);

    if (pr_fsio_lstat(src_path, &st) < 0) {
      pr_log_debug(DEBUG3, MOD_COPY_VERSION
        ": unable to stat '%s' (%s), skipping", src_path, strerror(errno));
      continue;
    }

    /* Is this path to a directory? */
    if (S_ISDIR(st.st_mode)) {
      if (create_path(iter_pool, dst_path) < 0) {
        res = -1;
        break;
      }

      if (copy_dir(iter_pool, src_path, dst_path) < 0) {
        res = -1;
        break;
      }
      continue;

    /* Is this path to a regular file? */
    } else if (S_ISREG(st.st_mode)) {
      cmd_rec *cmd;

      /* Dispatch fake COPY command, e.g. for mod_quotatab */
      cmd = pr_cmd_alloc(iter_pool, 4, pstrdup(iter_pool, "SITE"),
        pstrdup(iter_pool, "COPY"), pstrdup(iter_pool, src_path),
        pstrdup(iter_pool, dst_path));
      cmd->arg = pstrcat(iter_pool, "COPY ", src_path, " ", dst_path, NULL);
      cmd->cmd_class = CL_WRITE;

      pr_response_clear(&resp_list);
      pr_response_clear(&resp_err_list);

      if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
        int xerrno = errno;

        pr_log_debug(DEBUG3, MOD_COPY_VERSION
          ": COPY of '%s' to '%s' blocked by COPY handler: %s", src_path,
          dst_path, strerror(xerrno));

        pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
        pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
        pr_response_clear(&resp_err_list);

        errno = xerrno;
        res = -1;
        break;

      } else {
        if (pr_fs_copy_file(src_path, dst_path) < 0) {
          pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
          pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
          pr_response_clear(&resp_err_list);

          res = -1;
          break;

        } else {
          char *abs_path;
          
          pr_cmd_dispatch_phase(cmd, POST_CMD, 0);
          pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
          pr_response_clear(&resp_list);

          /* Write a TransferLog entry as well. */

          pr_fs_clear_cache2(dst_path);
          pr_fsio_stat(dst_path, &st);

          abs_path = dir_abs_path(p, dst_path, TRUE);

          if (session.sf_flags & SF_ANON) {
            xferlog_write(0, session.c->remote_name, st.st_size, abs_path,
               (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'a',
               session.anon_user, 'c', "_");

          } else {
            xferlog_write(0, session.c->remote_name, st.st_size, abs_path,
              (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'r',
              session.user, 'c', "_");
          }
        }
      }

      continue;

    /* Is this path a symlink? */
    } else if (S_ISLNK(st.st_mode)) {
      if (copy_symlink(iter_pool, src_path, dst_path) < 0) {
        res = -1;
        break;
      }
      continue;

    /* All other file types are skipped */
    } else {
      pr_log_debug(DEBUG3, MOD_COPY_VERSION ": skipping supported file '%s'",
        src_path);
      continue;
    }
  }

  if (iter_pool != NULL) {
    destroy_pool(iter_pool);
  }

  closedir(dh);
  return res;
}
Example #22
0
static int create_path(pool *p, const char *path) {
  struct stat st;
  char *curr_path, *dup_path; 
 
  pr_fs_clear_cache2(path);
  if (pr_fsio_stat(path, &st) == 0) {
    return 0;
  }
 
  dup_path = pstrdup(p, path);

  curr_path = "/"; 
  while (dup_path &&
         *dup_path) {
    char *curr_dir;
    int res;
    cmd_rec *cmd;
    pool *sub_pool;

    pr_signals_handle();

    curr_dir = strsep(&dup_path, "/");
    curr_path = pdircat(p, curr_path, curr_dir, NULL);

    /* Dispatch fake C_MKD command, e.g. for mod_quotatab */
    sub_pool = pr_pool_create_sz(p, 64);
    cmd = pr_cmd_alloc(sub_pool, 2, pstrdup(sub_pool, C_MKD),
      pstrdup(sub_pool, curr_path));
    cmd->arg = pstrdup(cmd->pool, curr_path);
    cmd->cmd_class = CL_DIRS|CL_WRITE;

    pr_response_clear(&resp_list);
    pr_response_clear(&resp_err_list);

    res = pr_cmd_dispatch_phase(cmd, PRE_CMD, 0);
    if (res < 0) {
      int xerrno = errno;

      pr_log_debug(DEBUG3, MOD_COPY_VERSION
        ": creating directory '%s' blocked by MKD handler: %s", curr_path,
        strerror(xerrno));

      pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
      pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
      pr_response_clear(&resp_err_list);

      destroy_pool(sub_pool);

      errno = xerrno;
      return -1;
    }

    res = create_dir(curr_path);
    if (res < 0) {
      pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
      pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
      pr_response_clear(&resp_err_list);

      destroy_pool(sub_pool);
      return -1;
    }

    pr_cmd_dispatch_phase(cmd, POST_CMD, 0);
    pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
    pr_response_clear(&resp_list);
    destroy_pool(sub_pool);
  }

  return 0;
}
Example #23
0
static array_header *get_sql_filters(pool *p, const char *query_name) {
  register unsigned int i;
  cmdtable *sql_cmdtab = NULL;
  cmd_rec *sql_cmd = NULL;
  modret_t *sql_res = NULL;
  array_header *sql_data = NULL;
  const char **values = NULL;
  array_header *sql_filters = NULL;

  sql_cmdtab = pr_stash_get_symbol2(PR_SYM_HOOK, "sql_lookup", NULL, NULL,
    NULL);
  if (sql_cmdtab == NULL) {
    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "unable to execute SQLNamedQuery '%s': mod_sql not loaded", query_name);
    errno = EPERM;
    return NULL;
  }

  sql_cmd = pr_cmd_alloc(p, 2, "sql_lookup", query_name);

  sql_res = pr_module_call(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);
  if (sql_res == NULL ||
      MODRET_ISERROR(sql_res)) {
    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "error processing SQLNamedQuery '%s'; check mod_sql logs for details",
      query_name);
    errno = EPERM;
    return NULL;
  }

  sql_data = sql_res->data;
  pr_trace_msg(trace_channel, 9, "SQLNamedQuery '%s' returned item count %d",
    query_name, sql_data->nelts);

  if (sql_data->nelts == 0) {
    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "SQLNamedQuery '%s' returned no values", query_name);
    errno = ENOENT;
    return NULL;
  }

  if (sql_data->nelts % 2 == 1) {
    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "SQLNamedQuery '%s' returned odd number of values (%d), "
      "expected even number", query_name, sql_data->nelts);
    errno = EINVAL;
    return NULL;
  }

  values = sql_data->elts;
  sql_filters = make_array(p, 0, sizeof(struct geoip_filter));

  for (i = 0; i < sql_data->nelts; i += 2) {
    const char *filter_name, *pattern = NULL;
    struct geoip_filter *filter;

    filter_name = values[i];
    pattern = values[i+1];

    filter = make_filter(p, filter_name, pattern);
    if (filter == NULL) {
      pr_trace_msg(trace_channel, 3, "unable to use '%s %s' as filter: %s",
        filter_name, pattern, strerror(errno));
      continue;
    }

    *((struct geoip_filter **) push_array(sql_filters)) = filter;
  }

  return sql_filters;
}