Exemplo n.º 1
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;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
static int forward_connect(pool *p, struct proxy_session *proxy_sess,
    pr_response_t **resp, unsigned int *resp_nlines) {
  conn_t *server_conn = NULL;
  int banner_ok = TRUE, use_tls, xerrno = 0;
  pr_netaddr_t *dst_addr;
  array_header *other_addrs = NULL;

  dst_addr = proxy_sess->dst_addr;
  other_addrs = proxy_sess->other_addrs;

  server_conn = proxy_conn_get_server_conn(p, proxy_sess, dst_addr);
  if (server_conn == NULL) {
    xerrno = errno;

    if (other_addrs != NULL) {
      register unsigned int i;

      /* Try the other IP addresses for the requested name (if any) as well. */
      for (i = 0; i < other_addrs->nelts; i++) {
        dst_addr = ((pr_netaddr_t **) other_addrs->elts)[i];

        pr_trace_msg(trace_channel, 8,
          "attempting to connect to other address #%u (%s) for requested "
          "URI '%.100s'", i+1, pr_netaddr_get_ipstr(dst_addr),
          proxy_conn_get_uri(proxy_sess->dst_pconn));
        server_conn = proxy_conn_get_server_conn(p, proxy_sess, dst_addr);
        if (server_conn != NULL) {
          proxy_sess->dst_addr = dst_addr;
          break;
        }
      }
    }

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

      /* EINVALs lead to strange-looking error responses; change them to
       * EPERM.
       */
      if (xerrno == EINVAL) {
        xerrno = EPERM;
      }
    }

    errno = xerrno;
    return -1;
  }

  /* XXX Support/send a CLNT command of our own?  Configurable via e.g.
   * "UserAgent" string?
   */

  proxy_sess->frontend_ctrl_conn = session.c;
  proxy_sess->backend_ctrl_conn = server_conn;

  /* Read the response from the backend server. */
  *resp = proxy_ftp_ctrl_recv_resp(p, proxy_sess->backend_ctrl_conn,
    resp_nlines);
  if (*resp == NULL) {
    xerrno = errno;

    pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "unable to read banner from server %s:%u: %s",
      pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr),
      ntohs(pr_netaddr_get_port(proxy_sess->backend_ctrl_conn->remote_addr)),
      strerror(xerrno));

    errno = EPERM;
    return -1;
  }

  if ((*resp)->num[0] != '2') {
    banner_ok = FALSE;
  }

  (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
    "received banner from backend %s:%u%s: %s %s",
    pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr),
    ntohs(pr_netaddr_get_port(proxy_sess->backend_ctrl_conn->remote_addr)),
    banner_ok ? "" : ", DISCONNECTING", (*resp)->num, (*resp)->msg);

  if (banner_ok == FALSE) {
    pr_inet_close(p, proxy_sess->backend_ctrl_conn);
    proxy_sess->backend_ctrl_conn = NULL;

    errno = EPERM;
    return -1;
  }

  /* Get the features supported by the backend server */
  if (proxy_ftp_sess_get_feat(p, proxy_sess) < 0) {
    if (errno != EPERM) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "unable to determine features of backend server: %s", strerror(errno));
    }
  }

  use_tls = proxy_tls_use_tls();
  if (use_tls != PROXY_TLS_ENGINE_OFF) {
    if (proxy_ftp_sess_send_auth_tls(p, proxy_sess) < 0) {
      xerrno = errno;

      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "error enabling TLS on control connection to backend server: %s",
        strerror(xerrno));
      pr_inet_close(p, proxy_sess->backend_ctrl_conn);
      proxy_sess->backend_ctrl_conn = NULL;

      *resp = NULL;
      errno = xerrno;
      return -1;
    }
  }

  if (proxy_netio_postopen(server_conn->instrm) < 0) {
    xerrno = errno;

    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "postopen error for backend control connection input stream: %s",
      strerror(xerrno));
    proxy_inet_close(session.pool, server_conn);
    proxy_sess->backend_ctrl_conn = NULL;

    *resp = NULL;
    errno = xerrno;
    return -1;
  }

  if (proxy_netio_postopen(server_conn->outstrm) < 0) {
    xerrno = errno;

    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "postopen error for backend control connection output stream: %s",
      strerror(xerrno));
    proxy_inet_close(session.pool, server_conn);
    proxy_sess->backend_ctrl_conn = NULL;

    *resp = NULL;
    errno = xerrno;
    return -1;
  }

  if (use_tls != PROXY_TLS_ENGINE_OFF) {
    if (proxy_sess_state & PROXY_SESS_STATE_BACKEND_HAS_CTRL_TLS) {
      /* NOTE: should this be a fatal error? */
      (void) proxy_ftp_sess_send_pbsz_prot(p, proxy_sess);
    }
  }

  (void) proxy_ftp_sess_send_host(p, proxy_sess);

  proxy_sess_state |= PROXY_SESS_STATE_CONNECTED;
  return 0;
}