Beispiel #1
0
int proxy_db_finish_stmt(pool *p, const char *stmt) {
  sqlite3_stmt *pstmt;
  int res;

  if (p == NULL ||
      stmt == NULL) {
    errno = EINVAL;
    return -1;
  }

  if (prepared_stmts == NULL) {
    errno = ENOENT;
    return -1;
  }

  pstmt = pr_table_get(prepared_stmts, stmt, NULL);
  if (pstmt == NULL) {
    pr_trace_msg(trace_channel, 19,
      "unable to find prepared statement for '%s'", stmt);
    errno = ENOENT;
    return -1;
  }

  res = sqlite3_finalize(pstmt);
  if (res != SQLITE_OK) {
    pr_trace_msg(trace_channel, 3,
      "error finishing prepared statement '%s': %s", stmt,
      sqlite3_errmsg(proxy_dbh));
    errno = EPERM;
    return -1;
  }

  (void) pr_table_remove(prepared_stmts, stmt, NULL); 
  return 0;
}
Beispiel #2
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);
}
Beispiel #3
0
int pr_var_delete(const char *name) {
  if (var_tab == NULL) {
    errno = EPERM;
    return -1;
  }

  if (name == NULL) {
    errno = EINVAL;
    return -1;
  }

  return pr_table_remove(var_tab, name, NULL) ? 0 : -1;
}
Beispiel #4
0
int pr_var_remove(const char *name) {
  if (!name) {
    errno = EINVAL;
    return -1;
  }

  if (!var_tab) {
    errno = EPERM;
    return -1;
  }

  return pr_table_remove(var_tab, name, NULL) ? 0 : -1;
}
Beispiel #5
0
MODRET copy_log_site(cmd_rec *cmd) {
  if (copy_engine == FALSE) {
    return PR_DECLINED(cmd);
  }

  if (cmd->argc < 3 ||
      strncasecmp(cmd->argv[1], "CPTO", 5) != 0) {
    return PR_DECLINED(cmd);
  }

  /* Delete the stashed CPFR path from the session.notes table. */
  (void) pr_table_remove(session.notes, "mod_copy.cpfr-path", NULL);

  return PR_DECLINED(cmd);
}
Beispiel #6
0
int pr_trace_set_levels(const char *channel, int min_level, int max_level) {

  if (channel == NULL) {
    void *v;

    if (trace_tab == NULL) {
      errno = EINVAL;
      return -1;
    }

    v = pr_table_remove(trace_tab, channel, NULL);
    if (v == NULL) {
      errno = EINVAL;
      return -1;
    }

    return 0;
  }

  if (min_level > max_level) {
    errno = EINVAL;
    return -1;
  }

  if (trace_tab == NULL &&
      min_level < 0) {
    return 0;
  }

  if (trace_pool == NULL) {
    trace_pool = make_sub_pool(permanent_pool);
    pr_pool_tag(trace_pool, "Trace API");

    trace_tab = pr_table_alloc(trace_pool, 0);

    /* Register a handler for churning the log pool during HUP. */
    pr_event_register(NULL, "core.restart", trace_restart_ev, NULL);
  }

  if (min_level >= 0) {
    struct trace_levels *levels;

    levels = pcalloc(trace_pool, sizeof(struct trace_levels));
    levels->min_level = min_level;
    levels->max_level = max_level;

    if (strcmp(channel, PR_TRACE_DEFAULT_CHANNEL) != 0) {
      int count = pr_table_exists(trace_tab, channel);

      if (count <= 0) {
        if (pr_table_add(trace_tab, pstrdup(trace_pool, channel), levels,
            sizeof(struct trace_levels)) < 0) {
          return -1;
        }

      } else {
        if (pr_table_set(trace_tab, pstrdup(trace_pool, channel), levels,
            sizeof(struct trace_levels)) < 0)
          return -1;
      }

    } else {
      register unsigned int i;

      for (i = 0; trace_channels[i]; i++) {
        (void) pr_trace_set_levels(trace_channels[i], min_level, max_level);
      }
    }

  } else {
    if (strcmp(channel, PR_TRACE_DEFAULT_CHANNEL) != 0) {
      (void) pr_table_remove(trace_tab, channel, NULL);

    } else {
      register unsigned int i;

      for (i = 0; trace_channels[i]; i++) {
        (void) pr_table_remove(trace_tab, trace_channels[i], NULL);
      }
    }
  }

  return 0;
}
Beispiel #7
0
conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess,
    pr_netaddr_t *remote_addr) {
  pr_netaddr_t *bind_addr = NULL, *local_addr = NULL;
  const char *remote_ipstr = NULL;
  unsigned int remote_port;
  conn_t *server_conn, *ctrl_conn;
  int res;

  if (proxy_sess->connect_timeout > 0) {
    const char *notes_key = "mod_proxy.proxy-connect-address";

    proxy_sess->connect_timerno = pr_timer_add(proxy_sess->connect_timeout,
      -1, &proxy_module, proxy_conn_connect_timeout_cb, "ProxyTimeoutConnect");

    (void) pr_table_remove(session.notes, notes_key, NULL);

    if (pr_table_add(session.notes, notes_key, remote_addr,
        sizeof(pr_netaddr_t)) < 0) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "error stashing proxy connect address note: %s", strerror(errno));
    }
  }

  remote_ipstr = pr_netaddr_get_ipstr(remote_addr);
  remote_port = ntohs(pr_netaddr_get_port(remote_addr));

  /* Check the family of the retrieved address vs what we'll be using
   * to connect.  If there's a mismatch, we need to get an addr with the
   * matching family.
   */

  if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(remote_addr)) {
    local_addr = session.c->local_addr;

  } else {
    /* In this scenario, the proxy has an IPv6 socket, but the remote/backend
     * server has an IPv4 (or IPv4-mapped IPv6) address.  OR it's the proxy
     * which has an IPv4 socket, and the remote/backend server has an IPv6
     * address.
     */
    if (pr_netaddr_get_family(session.c->local_addr) == AF_INET) {
      char *ip_str;

      /* Convert the local address from an IPv4 to an IPv6 addr. */
      ip_str = pcalloc(p, INET6_ADDRSTRLEN + 1);
      snprintf(ip_str, INET6_ADDRSTRLEN, "::ffff:%s",
        pr_netaddr_get_ipstr(session.c->local_addr));
      local_addr = pr_netaddr_get_addr(p, ip_str, NULL);

    } else {
      local_addr = pr_netaddr_v6tov4(p, session.c->local_addr);
      if (local_addr == NULL) {
        pr_trace_msg(trace_channel, 4,
          "error converting IPv6 local address %s to IPv4 address: %s",
          pr_netaddr_get_ipstr(session.c->local_addr), strerror(errno));
      }
    }

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

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

  /* Note: IF mod_proxy is running on localhost, and the connection to be
   * made is to a public IP address, then this connect(2) attempt would most
   * likely fail with ENETUNREACH, since localhost is a loopback network,
   * and of course not reachable from a public IP.  Thus we check for this
   * edge case (which happens often for development).
   */
  if (pr_netaddr_is_loopback(bind_addr) == TRUE) {
    const char *local_name;
    pr_netaddr_t *local_addr;

    local_name = pr_netaddr_get_localaddr_str(p);
    local_addr = pr_netaddr_get_addr(p, local_name, NULL);

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

  server_conn = pr_inet_create_conn(p, -1, bind_addr, INPORT_ANY, FALSE);
  if (server_conn == NULL) {
    int xerrno = errno;

    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "error creating connection to %s: %s", pr_netaddr_get_ipstr(bind_addr),
      strerror(xerrno));

    pr_timer_remove(proxy_sess->connect_timerno, &proxy_module);
    errno = xerrno;
    return NULL;
  }

  pr_trace_msg(trace_channel, 11, "connecting to backend address %s#%u from %s",
    remote_ipstr, remote_port, pr_netaddr_get_ipstr(bind_addr));

  res = pr_inet_connect_nowait(p, server_conn, remote_addr,
    ntohs(pr_netaddr_get_port(remote_addr)));
  if (res < 0) {
    int xerrno = errno;

    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "error starting connect to %s#%u: %s", remote_ipstr, remote_port,
      strerror(xerrno));

    pr_timer_remove(proxy_sess->connect_timerno, &proxy_module);
    errno = xerrno;
    return NULL;
  }

  if (res == 0) {
    pr_netio_stream_t *nstrm;
    int nstrm_mode = PR_NETIO_IO_RD;

    if (proxy_opts & PROXY_OPT_USE_PROXY_PROTOCOL) {
      /* Rather than waiting for the stream to be readable (because the
       * other end sent us something), wait for the stream to be writable
       * so that we can send something to the other end).
       */
      nstrm_mode = PR_NETIO_IO_WR;
    }

    /* Not yet connected. */
    nstrm = proxy_netio_open(p, PR_NETIO_STRM_OTHR, server_conn->listen_fd,
      nstrm_mode);
    if (nstrm == NULL) {
      int xerrno = errno;

      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "error opening stream to %s#%u: %s", remote_ipstr, remote_port,
        strerror(xerrno));

      pr_timer_remove(proxy_sess->connect_timerno, &proxy_module);
      pr_inet_close(p, server_conn);

      errno = xerrno;
      return NULL;
    }

    proxy_netio_set_poll_interval(nstrm, 1);

    switch (proxy_netio_poll(nstrm)) {
      case 1: {
        /* Aborted, timed out.  Note that we shouldn't reach here. */
        pr_timer_remove(proxy_sess->connect_timerno, &proxy_module);
        proxy_netio_close(nstrm);
        pr_inet_close(p, server_conn);

        errno = ETIMEDOUT;
        return NULL;
      }

      case -1: {
        /* Error */
        int xerrno = errno;

        (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
          "error connecting to %s#%u: %s", remote_ipstr, remote_port,
          strerror(xerrno));

        pr_timer_remove(proxy_sess->connect_timerno, &proxy_module);
        proxy_netio_close(nstrm);
        pr_inet_close(p, server_conn);

        errno = xerrno;
        return NULL;
      }

      default: {
        /* Connected */
        server_conn->mode = CM_OPEN;
        pr_timer_remove(proxy_sess->connect_timerno, &proxy_module);
        pr_table_remove(session.notes, "mod_proxy.proxy-connect-addr", NULL);

        res = pr_inet_get_conn_info(server_conn, server_conn->listen_fd);
        if (res < 0) {
          int xerrno = errno;

          (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
            "error obtaining local socket info on fd %d: %s",
            server_conn->listen_fd, strerror(xerrno));

          proxy_netio_close(nstrm);
          pr_inet_close(p, server_conn);

          errno = xerrno;
          return NULL;
        }

        break;
      }
    }
  }

  pr_trace_msg(trace_channel, 5,
    "successfully connected to %s#%u from %s#%d", remote_ipstr, remote_port,
    pr_netaddr_get_ipstr(server_conn->local_addr),
    ntohs(pr_netaddr_get_port(server_conn->local_addr)));

  ctrl_conn = proxy_inet_openrw(p, server_conn, NULL, PR_NETIO_STRM_CTRL, -1,
    -1, -1, FALSE);
  if (ctrl_conn == NULL) {
    int xerrno = errno;

    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "unable to open control connection to %s#%u: %s", remote_ipstr,
      remote_port, strerror(xerrno));

    pr_inet_close(p, server_conn);

    errno = xerrno;
    return NULL;
  }

  return ctrl_conn;
}