Exemplo n.º 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;
}
Exemplo n.º 2
0
const char *pr_session_get_protocol(int flags) {
  const char *sess_proto;

  sess_proto = pr_table_get(session.notes, "protocol", NULL);
  if (sess_proto == NULL) {
    sess_proto = "ftp";
  }

  if (!(flags & PR_SESS_PROTO_FL_LOGOUT)) {
    /* Return the protocol as is. */
    return sess_proto;
  }

  /* Otherwise, we need to return either "FTP" or "SSH2", for consistency. */
  if (strncmp(sess_proto, "ftp", 4) == 0 ||
      strncmp(sess_proto, "ftps", 5) == 0) {
    return "FTP";
  
  } else if (strncmp(sess_proto, "ssh2", 5) == 0 ||
             strncmp(sess_proto, "sftp", 5) == 0 ||
             strncmp(sess_proto, "scp", 4) == 0 ||
             strncmp(sess_proto, "publickey", 10) == 0) {
    return "SSH2";
  }

  /* Should never reach here, but just in case... */
  return "unknown";
}
Exemplo n.º 3
0
const char *pr_session_get_ttyname(pool *p) {
  char ttybuf[32];
  const char *sess_proto, *tty_proto = NULL;

  if (p == NULL) {
    errno = EINVAL;
    return NULL;
  }

  if (sess_ttyname) {
    /* Return the cached name. */
    return pstrdup(p, sess_ttyname);
  }

  sess_proto = pr_table_get(session.notes, "protocol", NULL);
  if (sess_proto) {
    if (strncmp(sess_proto, "ftp", 4) == 0 ||
        strncmp(sess_proto, "ftps", 5) == 0) {
#if (defined(BSD) && (BSD >= 199103))
      tty_proto = "ftp";
#else
      tty_proto = "ftpd";
#endif

    } else if (strncmp(sess_proto, "ssh2", 5) == 0 ||
               strncmp(sess_proto, "sftp", 5) == 0 ||
               strncmp(sess_proto, "scp", 4) == 0 ||
               strncmp(sess_proto, "publickey", 10) == 0) {

      /* Just use the plain "ssh" string for the tty name for these cases. */
      tty_proto = "ssh";

      /* Cache the originally constructed tty name for any later retrievals. */
      sess_ttyname = pstrdup(session.pool, tty_proto);
      return pstrdup(p, sess_ttyname);
    }
  }

  if (tty_proto == NULL) {
#if (defined(BSD) && (BSD >= 199103))
    tty_proto = "ftp";
#else
    tty_proto = "ftpd";
#endif
  }

  memset(ttybuf, '\0', sizeof(ttybuf));
#if (defined(BSD) && (BSD >= 199103))
  snprintf(ttybuf, sizeof(ttybuf), "%s%ld", tty_proto,
    (long) (session.pid ? session.pid : getpid()));
#else
  snprintf(ttybuf, sizeof(ttybuf), "%s%d", tty_proto,
    (int) (session.pid ? session.pid : getpid()));
#endif

  /* Cache the originally constructed tty name for any later retrievals. */
  sess_ttyname = pstrdup(session.pool, ttybuf);

  return pstrdup(p, sess_ttyname);
}
Exemplo n.º 4
0
Arquivo: var.c Projeto: OPSF/uClinux
const char *pr_var_get(const char *name) {
  struct var *v;

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

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

  v = pr_table_get(var_tab, name, NULL);
  if (!v)
    return NULL;

  switch (v->v_type) {
    case PR_VAR_TYPE_STR:
      return (const char *) v->v_val;
      break;

    case PR_VAR_TYPE_FUNC:
      return ((var_vstr_cb) v->v_val)(v->v_data, v->v_datasz);
      break;

    default:
      /* Pass through to the error case. */
      ;
  }

  errno = EINVAL;
  return NULL;
}
Exemplo n.º 5
0
static int forward_handle_pass_userwithproxyauth(cmd_rec *cmd,
    struct proxy_session *proxy_sess, int *successful, int *block_responses) {

  if (!(proxy_sess_state & PROXY_SESS_STATE_PROXY_AUTHENTICATED)) {
    int res;
    char *user;

    user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);

    res = proxy_session_check_password(cmd->pool, user, cmd->arg);
    if (res < 0) {
      errno = EINVAL;
      return -1;
    }

    res = proxy_session_setup_env(proxy_pool, user,
      PROXY_SESSION_FL_CHECK_LOGIN_ACL);
    if (res < 0) {
      errno = EINVAL;
      return -1;
    }

    if (session.auth_mech) {
      pr_log_debug(DEBUG2, "user '%s' authenticated by %s", user,
        session.auth_mech);
    }

    pr_response_send(R_230, _("User %s logged in"), user);
    return 1;
  }

  return forward_handle_pass_passthru(cmd, proxy_sess, successful);
}
Exemplo n.º 6
0
int proxy_forward_sess_init(pool *p, const char *tables_dir,
    struct proxy_session *proxy_sess) {
  config_rec *c;
  int allowed = FALSE;
  void *enabled = NULL;

  /* By default, only allow connections from RFC1918 addresses to use
   * forward proxying.  Otherwise, it must be from an explicitly allowed
   * connection class, via the class notes.
   */
  if (session.conn_class != NULL) {
    enabled = pr_table_get(session.conn_class->cls_notes,
      PROXY_FORWARD_ENABLED_NOTE, NULL);
  }

  if (enabled != NULL) {
    allowed = *((int *) enabled);
    if (allowed == FALSE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "forward proxying not allowed from client address %s in <Class %s> "
        "(see ProxyForwardEnabled)",
        pr_netaddr_get_ipstr(session.c->remote_addr),
        session.conn_class->cls_name);
    }

  } else {
    if (pr_netaddr_is_rfc1918(session.c->remote_addr) == TRUE) {
      allowed = TRUE;

    } else {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "forward proxying not allowed from non-RFC1918 client address %s",
        pr_netaddr_get_ipstr(session.c->remote_addr));
    }
  }

  if (allowed == FALSE) {
    errno = EPERM;
    return -1;
  }

  c = find_config(main_server->conf, CONF_PARAM, "ProxyForwardMethod", FALSE);
  if (c != NULL) {
    proxy_method = *((int *) c->argv[0]);
  }

  c = find_config(main_server->conf, CONF_PARAM, "ProxyRetryCount", FALSE);
  if (c != NULL) {
    forward_retry_count = *((int *) c->argv[0]);
  }

  return 0;
}
Exemplo n.º 7
0
int proxy_conn_connect_timeout_cb(CALLBACK_FRAME) {
  struct proxy_session *proxy_sess;
  pr_netaddr_t *server_addr;

  proxy_sess = pr_table_get(session.notes, "mod_proxy.proxy-session", NULL);
  server_addr = pr_table_get(session.notes, "mod_proxy.proxy-connect-address",
    NULL);

  (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
    "timed out connecting to %s:%d after %d %s",
    pr_netaddr_get_ipstr(server_addr), ntohs(pr_netaddr_get_port(server_addr)),
    proxy_sess->connect_timeout,
    proxy_sess->connect_timeout != 1 ? "seconds" : "second");

  pr_event_generate("mod_proxy.timeout-connect", NULL);

  pr_log_pri(PR_LOG_NOTICE, "%s", "Connect timed out, disconnected");
  pr_session_disconnect(&proxy_module, PR_SESS_DISCONNECT_TIMEOUT,
    "ProxyTimeoutConnect");

  /* Do not restart the timer (should never be reached). */
  return 0;
}
Exemplo n.º 8
0
int proxy_db_prepare_stmt(pool *p, const char *stmt) {
  sqlite3_stmt *pstmt = NULL;
  int res;

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

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

    return 0;
  }

  res = sqlite3_prepare_v2(proxy_dbh, stmt, -1, &pstmt, NULL);
  if (res != SQLITE_OK) {
    pr_trace_msg(trace_channel, 4,
      "error preparing statement '%s': %s", stmt, sqlite3_errmsg(proxy_dbh));
    errno = EINVAL;
    return -1;
  }

  /* The prepared statement handling here relies on this cache, thus if we fail
   * to stash the prepared statement here, it will cause problems later.
   */
  res = pr_table_add(prepared_stmts, pstrdup(db_pool, stmt), pstmt,
    sizeof(sqlite3_stmt *));
  if (res < 0) {
    int xerrno = errno;
    pr_trace_msg(trace_channel, 4,
      "error stashing prepared statement '%s': %s", stmt, strerror(xerrno));
    errno = xerrno;
    return -1; 
  }

  return 0; 
}
Exemplo n.º 9
0
Arquivo: var.c Projeto: rogerhu/dd-wrt
const char *pr_var_next(const char **desc) {
  const char *name;
  struct var *v;

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

  name = pr_table_next(var_tab);
  if (!name)
    return NULL;

  v = pr_table_get(var_tab, name, NULL);
  if (v && desc)
    *desc = v->v_desc;

  return name;
}
Exemplo n.º 10
0
int pr_auth_authorize(pool *p, const char *name) {
  cmd_rec *cmd = NULL;
  modret_t *mr = NULL;
  module *m = NULL;
  int res = PR_AUTH_OK;

  cmd = make_cmd(p, 1, name);

  if (auth_tab) {

    /* Fetch the specific module to be used for authenticating this user. */
    void *v = pr_table_get(auth_tab, name, NULL);
    if (v) {
      m = *((module **) v);

      pr_trace_msg(trace_channel, 4,
        "using module 'mod_%s.c' from authcache to authorize user '%s'",
        m->name, name);
    }
  }

  mr = dispatch_auth(cmd, "authorize", m ? &m : NULL);

  /* Unlike the other auth calls, we assume here that unless the handlers
   * explicitly return ERROR, the user is authorized.  Thus HANDLED and
   * DECLINED are both treated as "yes, this user is authorized".  This
   * handles the case where the authenticating module (e.g. mod_sql)
   * does NOT provide an 'authorize' handler.
   */

  if (MODRET_ISERROR(mr)) {
    res = MODRET_ERROR(mr);
  }

  if (cmd->tmp_pool) {
    destroy_pool(cmd->tmp_pool);
    cmd->tmp_pool = NULL;
  }

  return res;
}
Exemplo n.º 11
0
const char *pr_var_next(const char **desc) {
  const char *name;
  struct var *v;

  if (var_tab == NULL) {
    errno = EPERM;
    return NULL;
  }

  name = pr_table_next(var_tab);
  if (name == NULL) {
    return NULL;
  }

  v = pr_table_get(var_tab, name, NULL);
  if (v && desc) {
    *desc = v->v_desc;
  }

  return name;
}
Exemplo n.º 12
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;
}
Exemplo n.º 13
0
static struct trace_levels *trace_get_levels(const char *channel) {
  void *value;

  if (channel == NULL) {
    errno = EINVAL;
    return NULL;
  }

  if (trace_tab == NULL ||
      trace_logfd < 0) {
    errno = EPERM;
    return NULL;
  }

  value = pr_table_get(trace_tab, channel, NULL);
  if (value == NULL) {
    errno = ENOENT;
    return NULL;
  }

  return value;
}
Exemplo n.º 14
0
const char *pr_var_get(const char *name) {
  struct var *v = NULL;

  if (var_tab == NULL) {
    errno = EPERM;
    return NULL;
  }

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

  v = pr_table_get(var_tab, name, NULL);
  if (v == NULL) {
    return NULL;
  }

  switch (v->v_type) {
    case PR_VAR_TYPE_STR:
      return (const char *) v->v_val;
      break;

    case PR_VAR_TYPE_FUNC:
      return ((var_vstr_cb) v->v_val)(v->v_data, v->v_datasz);
      break;

    default:
      /* Pass through to the error case. */
      pr_trace_msg(trace_channel, 9,
        "unknown var type (%d) found for name '%s'", v->v_type, name);
  }

  errno = EINVAL;
  return NULL;
}
Exemplo n.º 15
0
array_header *proxy_db_exec_prepared_stmt(pool *p, const char *stmt,
    const char **errstr) {
  sqlite3_stmt *pstmt;
  int readonly = FALSE, res;
  array_header *results = NULL;

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

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

  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 NULL;
  }

  readonly = sqlite3_stmt_readonly(pstmt);
  if (!readonly) {
    /* Assume this is an INSERT/UPDATE/DELETE. */
    res = sqlite3_step(pstmt);
    if (res != SQLITE_DONE) {
      const char *errmsg;

      errmsg = sqlite3_errmsg(proxy_dbh);
      if (errstr) {
        *errstr = pstrdup(p, errmsg);
      }
      pr_trace_msg(trace_channel, 2,
        "error executing '%s': %s", stmt, errmsg);
      errno = EPERM;
      return NULL;
    }

    /* Indicate success for non-readonly statements by returning an empty
     * result set.
     */
    pr_trace_msg(trace_channel, 13, "successfully executed '%s'", stmt);
    results = make_array(p, 0, sizeof(char *));
    return results;
  }

  results = make_array(p, 0, sizeof(char *));

  res = sqlite3_step(pstmt);
  while (res == SQLITE_ROW) {
    register unsigned int i;
    int ncols;

    ncols = sqlite3_column_count(pstmt);
    pr_trace_msg(trace_channel, 12,
      "executing prepared statement '%s' returned row (columns: %d)",
      stmt, ncols);

    for (i = 0; i < ncols; i++) {
      char *val = NULL;

      pr_signals_handle();

      /* By using sqlite3_column_text, SQLite will coerce the column value
       * into a string.
       */
      val = pstrdup(p, (const char *) sqlite3_column_text(pstmt, i));

      pr_trace_msg(trace_channel, 17,
        "column %s [%u]: %s", sqlite3_column_name(pstmt, i), i, val);
      *((char **) push_array(results)) = val;
    }

    res = sqlite3_step(pstmt);
  }

  if (res != SQLITE_DONE) {
    const char *errmsg;

    errmsg = sqlite3_errmsg(proxy_dbh);
    if (errstr != NULL) {
      *errstr = pstrdup(p, errmsg);
    }

    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "executing prepared statement '%s' did not complete successfully: %s",
      stmt, errmsg);
    errno = EPERM;
    return NULL;
  }

  pr_trace_msg(trace_channel, 13, "successfully executed '%s'", stmt);
  return results;
}
Exemplo n.º 16
0
MODRET counter_stor(cmd_rec *cmd) {
  config_rec *c;
  int res;
  pr_fh_t *fh;
  const char *path;

  if (counter_engine == FALSE) {
    return PR_DECLINED(cmd);
  }

  c = find_config(CURRENT_CONF, CONF_PARAM, "CounterMaxWriters", FALSE);
  counter_max_writers = c ? *((int *) c->argv[0]) : COUNTER_DEFAULT_MAX_WRITERS;

  if (counter_max_writers == 0) {
    return PR_DECLINED(cmd);
  }

  path = pr_table_get(cmd->notes, "mod_xfer.store-path", NULL);
  if (path == NULL) {
    return PR_DECLINED(cmd);
  }

  /* Note that for purposes of our semaphores, we need to use the absolute
   * path.
   */
  counter_curr_path = counter_abs_path(cmd->pool, path, FALSE);

  fh = counter_get_fh(cmd->tmp_pool, counter_curr_path);
  if (fh == NULL) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "%s: no CounterFile found for path '%s'", (char *) cmd->argv[0],
      counter_curr_path);

    /* No CounterFile configured/available for this path. */
    return PR_DECLINED(cmd);
  }

  counter_curr_semid = counter_get_sem(fh, counter_curr_path);
  if (counter_curr_semid < 0) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "unable to get semaphore for '%s': %s", counter_curr_path,
      strerror(errno));
    return PR_DECLINED(cmd);
  }

  /* Add a writer to this file by decrementing the writer counter value.
   * This functions as a sort of "lock".
   */
  res = counter_add_writer(counter_curr_semid);
  if (res < 0 &&
      errno == EAGAIN) {
  
    /* The lock acquisition failed, which means the file is busy.
     * The upload should be failed.
     */
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "%s: max number of writers (%d) reached for '%s'", (char *) cmd->argv[0],
      counter_max_writers, counter_curr_path);
    pr_response_add_err(R_450, _("%s: File busy"), cmd->arg);
    return PR_ERROR(cmd);
  }

  counter_pending |= COUNTER_HAVE_WRITER;
  (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
    "%s: added writer counter for '%s' (semaphore ID %d)",
    (char *) cmd->argv[0], counter_curr_path, counter_curr_semid);

  return PR_DECLINED(cmd);
}
Exemplo n.º 17
0
int pr_auth_check(pool *p, const char *cpw, const char *name, const char *pw) {
  cmd_rec *cmd = NULL;
  modret_t *mr = NULL;
  module *m = NULL;
  int res = PR_AUTH_BADPWD;

  cmd = make_cmd(p, 3, cpw, name, pw);

  /* First, check for any of the modules in the "authenticating only" list
   * of modules.  This is usually only mod_auth_pam, but other modules
   * might also add themselves (e.g. mod_radius under certain conditions).
   */
  if (auth_module_list) {
    struct auth_module_elt *elt;

    for (elt = (struct auth_module_elt *) auth_module_list->xas_list; elt;
        elt = elt->next) {

      m = pr_module_get(elt->name);
      if (m) {
        mr = dispatch_auth(cmd, "check", &m);

        if (MODRET_ISHANDLED(mr)) {
          pr_trace_msg(trace_channel, 4,
            "module '%s' used for authenticating user '%s'", elt->name, name);

          res = MODRET_HASDATA(mr) ? PR_AUTH_RFC2228_OK : PR_AUTH_OK;

          if (cmd->tmp_pool) {
            destroy_pool(cmd->tmp_pool);
            cmd->tmp_pool = NULL;
          }

          return res;
        }

        if (MODRET_ISERROR(mr)) {
          res = MODRET_ERROR(mr);

          if (cmd->tmp_pool) {
            destroy_pool(cmd->tmp_pool);
            cmd->tmp_pool = NULL;
          }

          return res;
        }

        m = NULL;
      }
    }
  }

  if (auth_tab) {

    /* Fetch the specific module to be used for authenticating this user. */
    void *v = pr_table_get(auth_tab, name, NULL);
    if (v) {
      m = *((module **) v);

      pr_trace_msg(trace_channel, 4,
        "using module 'mod_%s.c' from authcache to authenticate user '%s'",
        m->name, name);
    }
  }

  mr = dispatch_auth(cmd, "check", m ? &m : NULL);

  if (MODRET_ISHANDLED(mr))
    res = MODRET_HASDATA(mr) ? PR_AUTH_RFC2228_OK : PR_AUTH_OK;

  if (cmd->tmp_pool) {
    destroy_pool(cmd->tmp_pool);
    cmd->tmp_pool = NULL;
  }

  return res;
}
Exemplo n.º 18
0
static int display_fh(pr_fh_t *fh, const char *fs, const char *code,
    int flags) {
  struct stat st;
  char buf[PR_TUNABLE_BUFFER_SIZE] = {'\0'};
  int len, res;
  unsigned int *current_clients = NULL;
  unsigned int *max_clients = NULL;
  off_t fs_size = 0;
  pool *p;
  void *v;
  xaset_t *s;
  config_rec *c = NULL;
  const char *serverfqdn = main_server->ServerFQDN;
  char *outs, mg_size[12] = {'\0'}, mg_size_units[12] = {'\0'},
    mg_max[12] = "unlimited";
  char total_files_in[12] = {'\0'}, total_files_out[12] = {'\0'},
    total_files_xfer[12] = {'\0'};
  char mg_class_limit[12] = {'\0'}, mg_cur[12] = {'\0'},
    mg_xfer_bytes[12] = {'\0'}, mg_cur_class[12] = {'\0'};
  char mg_xfer_units[12] = {'\0'}, *user;
  const char *mg_time;
  char *rfc1413_ident = NULL;

  /* Stat the opened file to determine the optimal buffer size for IO. */
  memset(&st, 0, sizeof(st));
  if (pr_fsio_fstat(fh, &st) == 0) {
    fh->fh_iosz = st.st_blksize;
  }

  /* Note: The size provided by pr_fs_getsize() is in KB, not bytes. */
  res = pr_fs_fgetsize(fh->fh_fd, &fs_size);
  if (res < 0 &&
      errno != ENOSYS) {
    (void) pr_log_debug(DEBUG7, "error getting filesystem size for '%s': %s",
      fh->fh_path, strerror(errno));
    fs_size = 0;
  }

  snprintf(mg_size, sizeof(mg_size), "%" PR_LU, (pr_off_t) fs_size);
  format_size_str(mg_size_units, sizeof(mg_size_units), fs_size);

  p = make_sub_pool(session.pool);
  pr_pool_tag(p, "Display Pool");

  s = (session.anon_config ? session.anon_config->subset : main_server->conf);

  mg_time = pr_strtime(time(NULL));

  max_clients = get_param_ptr(s, "MaxClients", FALSE);

  v = pr_table_get(session.notes, "client-count", NULL);
  if (v) {
    current_clients = v;
  }

  snprintf(mg_cur, sizeof(mg_cur), "%u", current_clients ? *current_clients: 1);

  if (session.conn_class != NULL &&
      session.conn_class->cls_name != NULL) {
    unsigned int *class_clients = NULL;
    config_rec *maxc = NULL;
    unsigned int maxclients = 0;

    v = pr_table_get(session.notes, "class-client-count", NULL);
    if (v) {
      class_clients = v;
    }

    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u",
      class_clients ? *class_clients : 0);

    /* For the %z variable, first we scan through the MaxClientsPerClass,
     * and use the first applicable one.  If none are found, look for
     * any MaxClients set.
     */

    maxc = find_config(main_server->conf, CONF_PARAM, "MaxClientsPerClass",
      FALSE);

    while (maxc) {
      pr_signals_handle();

      if (strcmp(maxc->argv[0], session.conn_class->cls_name) != 0) {
        maxc = find_config_next(maxc, maxc->next, CONF_PARAM,
          "MaxClientsPerClass", FALSE);
        continue;
      }

      maxclients = *((unsigned int *) maxc->argv[1]);
      break;
    }

    if (maxclients == 0) {
      maxc = find_config(main_server->conf, CONF_PARAM, "MaxClients", FALSE);

      if (maxc)
        maxclients = *((unsigned int *) maxc->argv[0]);
    }

    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", maxclients);

  } else {
    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u",
      max_clients ? *max_clients : 0);
    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", 0);
  }

  snprintf(mg_xfer_bytes, sizeof(mg_xfer_bytes), "%" PR_LU,
    (pr_off_t) session.total_bytes >> 10);
  snprintf(mg_xfer_units, sizeof(mg_xfer_units), "%" PR_LU "B",
    (pr_off_t) session.total_bytes);

  if (session.total_bytes >= 10240) {
    snprintf(mg_xfer_units, sizeof(mg_xfer_units), "%" PR_LU "kB",
      (pr_off_t) session.total_bytes >> 10);

  } else if ((session.total_bytes >> 10) >= 10240) {
Exemplo n.º 19
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;
}
Exemplo n.º 20
0
MODRET wrap_handle_request(cmd_rec *cmd) {

  /* these variables are names expected to be set by the TCP wrapper code
   */
  struct request_info request;

  char *user = NULL;
  config_rec *conf = NULL, *access_conf = NULL, *syslog_conf = NULL;
  hosts_allow_table = NULL;
  hosts_deny_table = NULL;

  /* hide passwords */
  session.hide_password = TRUE;

  /* Sneaky...found in mod_auth.c's cmd_pass() function.  Need to find the
   * login UID in order to resolve the possibly-login-dependent filename.
   */
  user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);

  /* It's possible that a PASS command came before USER.  This is a PRE_CMD
   * handler, so it won't be protected from this case; we'll need to do
   * it manually.
   */
  if (!user)
    return PR_DECLINED(cmd);

  /* Use mod_auth's _auth_resolve_user() [imported for use here] to get the
   * right configuration set, since the user may be logging in anonymously,
   * and the session struct hasn't yet been set for that yet (thus short-
   * circuiting the easiest way to get the right context...the macros.
   */
  conf = wrap_resolve_user(cmd->pool, &user);

  /* Search first for user-specific access files.  Multiple TCPUserAccessFiles
   * directives are allowed.
   */
  if ((access_conf = find_config(conf ? conf->subset : CURRENT_CONF, CONF_PARAM,
      "TCPUserAccessFiles", FALSE)) != NULL) {
    int matched = FALSE;
    array_header *user_array = NULL;

    while (access_conf) {

      user_array = make_array(cmd->tmp_pool, 0, sizeof(char *));
      *((char **) push_array(user_array)) = pstrdup(cmd->tmp_pool, user);

      /* Check the user expression -- don't forget the offset, to skip
       * the access file name strings in argv
       */
      if (wrap_eval_expression(((char **) access_conf->argv) + 2,
          user_array)) {
        pr_log_debug(DEBUG4, MOD_WRAP_VERSION
          ": matched TCPUserAccessFiles expression");
        matched = TRUE;
        break;
      }

      access_conf = find_config_next(access_conf, access_conf->next,
        CONF_PARAM, "TCPUserAccessFiles", FALSE);
    }

    if (!matched)
      access_conf = NULL;
  }

  /* Next, search for group-specific access files.  Multiple
   * TCPGroupAccessFiles directives are allowed.
   */ 
  if (!access_conf && (access_conf = find_config(conf ? conf->subset :
        CURRENT_CONF, CONF_PARAM, "TCPGroupAccessFiles", FALSE)) != NULL) {
    unsigned char matched = FALSE;

    /* NOTE: this gid_array is only necessary until Bug#1461 is fixed */
    array_header *gid_array = make_array(cmd->pool, 0, sizeof(gid_t));

    array_header *group_array = make_array(cmd->pool, 0, sizeof(char *));

    while (access_conf) {
      if (pr_auth_getgroups(cmd->pool, user, &gid_array, &group_array) < 1) {
        pr_log_debug(DEBUG3, MOD_WRAP_VERSION
          ": no supplemental groups found for user '%s'", user);

      } else {

        /* Check the group expression -- don't forget the offset, to skip
         * the access file names strings in argv
         */
        if (wrap_eval_expression(((char **) access_conf->argv) + 2,
            group_array)) {
          pr_log_debug(DEBUG4, MOD_WRAP_VERSION
            ": matched TCPGroupAccessFiles expression");
          matched = TRUE;
          break;
        }
      }

      access_conf = find_config_next(access_conf, access_conf->next,
        CONF_PARAM, "TCPGroupAccessFiles", FALSE);
    }

    if (!matched)
      access_conf = NULL;
  }

  /* Finally for globally-applicable access files.  Only one such directive
   * is allowed.
   */
  if (!access_conf) {
    access_conf = find_config(conf ? conf->subset : CURRENT_CONF,
      CONF_PARAM, "TCPAccessFiles", FALSE);
  }

  if (access_conf) {
    hosts_allow_table = (char *) access_conf->argv[0];
    hosts_deny_table = (char *) access_conf->argv[1];
  }

  /* Now, check the retrieved filename, and see if it requires a login-time
   * file.
   */
  if (hosts_allow_table != NULL && hosts_allow_table[0] == '~' &&
      hosts_allow_table[1] == '/') {
    char *allow_real_table = NULL;

    allow_real_table = wrap_get_user_table(cmd, user, hosts_allow_table);

    if (!wrap_is_usable_file(allow_real_table)) {
      pr_log_pri(PR_LOG_WARNING, MOD_WRAP_VERSION
        ": configured TCPAllowFile %s is unusable", hosts_allow_table);
      hosts_allow_table = NULL;

    } else
      hosts_allow_table = allow_real_table;
  }

  if (hosts_deny_table != NULL && hosts_deny_table[0] == '~' &&
      hosts_deny_table[1] == '/') {
    char *deny_real_table = NULL;

    deny_real_table = dir_realpath(cmd->pool, hosts_deny_table);

    if (!wrap_is_usable_file(deny_real_table)) {
      pr_log_pri(PR_LOG_WARNING, MOD_WRAP_VERSION
        ": configured TCPDenyFile %s is unusable", hosts_deny_table);
      hosts_deny_table = NULL;

    } else 
      hosts_deny_table = deny_real_table;
  }

  /* Make sure that _both_ allow and deny TCPAccessFiles are present.
   * If not, log the missing file, and by default allow request to succeed.
   */
  if (hosts_allow_table != NULL && hosts_deny_table != NULL) {

    /* Most common case...nothing more necessary */

  } else if (hosts_allow_table == NULL && hosts_deny_table != NULL) {

    /* Log the missing file */
    pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": no usable allow access file -- "
      "allowing connection");

    return PR_DECLINED(cmd);

  } else if (hosts_allow_table != NULL && hosts_deny_table == NULL) {

    /* log the missing file */
    pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": no usable deny access file -- "
      "allowing connection");

    return PR_DECLINED(cmd);

  } else {

    /* Neither set -- assume the admin hasn't configured these directives
     * at all.
     */
    return PR_DECLINED(cmd);
  }

  /* Log the names of the allow/deny files being used. */
  pr_log_pri(PR_LOG_DEBUG, MOD_WRAP_VERSION ": using access files: %s, %s",
    hosts_allow_table, hosts_deny_table);

  /* retrieve the user-defined syslog priorities, if any.  Fall back to the
   * defaults as seen in tcpd.h if not defined.
   */
  syslog_conf = find_config(main_server->conf, CONF_PARAM,
    "TCPAccessSyslogLevels", FALSE);

  if (syslog_conf) {
    allow_severity = *((int *) syslog_conf->argv[0]);
    deny_severity = *((int *) syslog_conf->argv[1]);

  } else {
    allow_severity = PR_LOG_INFO;
    deny_severity = PR_LOG_WARNING;
  }

  /* While it may look odd to OR together the syslog facility and level,
   * that is the way that syslog(3) says to do it:
   *
   *  "The priority argument is formed by ORing the facility and the level
   *   values..."
   *
   * Note that we do this OR here because the allow_severity/deny_severity
   * values are ALSO used by the libwrap library; it is also why we need
   * to mask off some bits later, when using proftpd's logging functions.
   */
  allow_severity = log_getfacility() | allow_severity;
  deny_severity = log_getfacility() | deny_severity;

  pr_log_debug(DEBUG4, MOD_WRAP_VERSION ": checking under service name '%s'",
    wrap_service_name);
  request_init(&request, RQ_DAEMON, wrap_service_name, RQ_FILE,
    session.c->rfd, 0);

  fromhost(&request);

  if (STR_EQ(eval_hostname(request.client), paranoid) ||
      !hosts_access(&request)) {
    char *denymsg = NULL;

    /* log the denied connection */
    wrap_log_request_denied(deny_severity, &request);

    /* Broadcast this event to any interested listeners. */
    pr_event_generate("mod_wrap.connection-denied", NULL);

    /* check for AccessDenyMsg */
    if ((denymsg = (char *) get_param_ptr(TOPLEVEL_CONF, "AccessDenyMsg",
        FALSE)) != NULL)
      denymsg = sreplace(cmd->tmp_pool, denymsg, "%u", user, NULL);

    if (denymsg)
      return PR_ERROR_MSG(cmd, R_530, denymsg);
    else
      return PR_ERROR_MSG(cmd, R_530, _("Access denied"));
  }

  /* If request is allowable, return DECLINED (for engine to act as if this
   * handler was never called, else ERROR (for engine to abort processing and
   * deny request.
   */
  wrap_log_request_allowed(allow_severity, &request);

  return PR_DECLINED(cmd);
}
Exemplo n.º 21
0
const char *sftp_display_fh_get_msg(pool *p, pr_fh_t *fh) {
  struct stat st;
  char buf[PR_TUNABLE_BUFFER_SIZE], *msg = "";
  int len, res;
  unsigned int *current_clients = NULL;
  unsigned int *max_clients = NULL;
  off_t fs_size = 0;
  void *v;
  const char *serverfqdn = main_server->ServerFQDN;
  char *outs, mg_size[12] = {'\0'}, mg_size_units[12] = {'\0'},
    mg_max[12] = "unlimited";
  char mg_class_limit[12] = {'\0'}, mg_cur[12] = {'\0'},
    mg_cur_class[12] = {'\0'};
  const char *mg_time;
  char *rfc1413_ident = NULL, *user = NULL;

  /* Stat the opened file to determine the optimal buffer size for IO. */
  memset(&st, 0, sizeof(st));
  if (pr_fsio_fstat(fh, &st) == 0) {
    fh->fh_iosz = st.st_blksize;
  }

  res = pr_fs_fgetsize(fh->fh_fd, &fs_size);
  if (res < 0 &&
      errno != ENOSYS) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error getting filesystem size for '%s': %s", fh->fh_path,
      strerror(errno));
    fs_size = 0;
  }

  snprintf(mg_size, sizeof(mg_size), "%" PR_LU, (pr_off_t) fs_size);
  format_size_str(mg_size_units, sizeof(mg_size_units), fs_size);

  mg_time = pr_strtime(time(NULL));

  max_clients = get_param_ptr(main_server->conf, "MaxClients", FALSE);

  v = pr_table_get(session.notes, "client-count", NULL);
  if (v) {
    current_clients = v;
  }

  snprintf(mg_cur, sizeof(mg_cur), "%u", current_clients ? *current_clients: 1);

  if (session.conn_class != NULL &&
      session.conn_class->cls_name) {
    unsigned int *class_clients = NULL;
    config_rec *maxc = NULL;
    unsigned int maxclients = 0;

    v = pr_table_get(session.notes, "class-client-count", NULL);
    if (v) {
      class_clients = v;
    }

    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u",
      class_clients ? *class_clients : 0);

    /* For the %z variable, first we scan through the MaxClientsPerClass,
     * and use the first applicable one.  If none are found, look for
     * any MaxClients set.
     */

    maxc = find_config(main_server->conf, CONF_PARAM, "MaxClientsPerClass",
      FALSE);

    while (maxc) {
      pr_signals_handle();

      if (strcmp(maxc->argv[0], session.conn_class->cls_name) != 0) {
        maxc = find_config_next(maxc, maxc->next, CONF_PARAM,
          "MaxClientsPerClass", FALSE);
        continue;
      }

      maxclients = *((unsigned int *) maxc->argv[1]);
      break;
    }

    if (maxclients == 0) {
      maxc = find_config(main_server->conf, CONF_PARAM, "MaxClients", FALSE);

      if (maxc)
        maxclients = *((unsigned int *) maxc->argv[0]);
    }

    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", maxclients);

  } else {
    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u",
      max_clients ? *max_clients : 0);
    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", 0);
  }

  snprintf(mg_max, sizeof(mg_max), "%u", max_clients ? *max_clients : 0);

  user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
  if (user == NULL)
    user = "";

  rfc1413_ident = pr_table_get(session.notes, "mod_ident.rfc1413-ident", NULL);
  if (rfc1413_ident == NULL) {
    rfc1413_ident = "UNKNOWN";
  }

  memset(buf, '\0', sizeof(buf));
  while (pr_fsio_gets(buf, sizeof(buf), fh) != NULL) {
    char *tmp;

    pr_signals_handle();

    buf[sizeof(buf)-1] = '\0';
    len = strlen(buf);

    while (len > 0 &&
           (buf[len-1] == '\r' || buf[len-1] == '\n')) {
      pr_signals_handle();

      buf[len-1] = '\0';
      len--;
    }

    /* Check for any Variable-type strings. */
    tmp = strstr(buf, "%{");
    while (tmp) {
      char *key, *tmp2;
      const char *val;

      pr_signals_handle();

      tmp2 = strchr(tmp, '}');
      if (tmp2 == NULL) {
        /* No closing '}' found in this string, so no need to look for any
         * aother '%{' opening sequence.  Just move on.
         */
        tmp = NULL;
        break;
      }

      key = pstrndup(p, tmp, tmp2 - tmp + 1);

      /* There are a couple of special-case keys to watch for:
       *
       *   env:$var
       *   time:$fmt
       *
       * The Var API does not easily support returning values for keys
       * where part of the value depends on part of the key.  That's why
       * these keys are handled here, instead of in pr_var_get().
       */

      if (strncmp(key, "%{time:", 7) == 0) {
        char time_str[128], *fmt;
        time_t now;
        struct tm *time_info;

        fmt = pstrndup(p, key + 7, strlen(key) - 8);

        now = time(NULL);
        time_info = pr_localtime(NULL, &now);

        memset(time_str, 0, sizeof(time_str));
        strftime(time_str, sizeof(time_str), fmt, time_info);

        val = pstrdup(p, time_str);

      } else if (strncmp(key, "%{env:", 6) == 0) {
        char *env_var;

        env_var = pstrndup(p, key + 6, strlen(key) - 7);
        val = pr_env_get(p, env_var);
        if (val == NULL) {
          pr_trace_msg("var", 4,
            "no value set for environment variable '%s', using \"(none)\"",
            env_var);
          val = "(none)";
        }

      } else {
        val = pr_var_get(key);
        if (val == NULL) {
          pr_trace_msg("var", 4,
            "no value set for name '%s', using \"(none)\"", key);
          val = "(none)";
        }
      }

      outs = sreplace(p, buf, key, val, NULL);
      sstrncpy(buf, outs, sizeof(buf));

      tmp = strstr(outs, "%{");
    }

    outs = sreplace(p, buf,
      "%C", (session.cwd[0] ? session.cwd : "(none)"),
      "%E", main_server->ServerAdmin,
      "%F", mg_size,
      "%f", mg_size_units,
      "%i", "0",
      "%K", "0",
      "%k", "0B",
      "%L", serverfqdn,
      "%M", mg_max,
      "%N", mg_cur,
      "%o", "0",
      "%R", (session.c && session.c->remote_name ?
        session.c->remote_name : "(unknown)"),
      "%T", mg_time,
      "%t", "0",
      "%U", user,
      "%u", rfc1413_ident,
      "%V", main_server->ServerName,
      "%x", session.conn_class ? session.conn_class->cls_name : "(unknown)",
      "%y", mg_cur_class,
      "%z", mg_class_limit,
      NULL);

    /* Always make sure that the lines we send are CRLF-terminated. */
    msg = pstrcat(p, msg, outs, "\r\n", NULL);

    /* Clear the buffer for the next read. */
    memset(buf, '\0', sizeof(buf));
  }

  return msg;
}
Exemplo n.º 22
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.º 23
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.º 24
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;
}
Exemplo n.º 25
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;
}
Exemplo n.º 26
0
int proxy_db_bind_stmt(pool *p, const char *stmt, int idx, int type,
    void *data) {
  sqlite3_stmt *pstmt;
  int res;
 
  if (p == NULL ||
      stmt == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* SQLite3 bind parameters start at index 1. */
  if (idx < 1) {
    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;
  }

  switch (type) {
    case PROXY_DB_BIND_TYPE_INT: {
      int i;

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

      i = *((int *) data);
      res = sqlite3_bind_int(pstmt, idx, i);
      if (res != SQLITE_OK) {
        pr_trace_msg(trace_channel, 4,
          "error binding parameter %d of '%s' to INT %d: %s", idx, stmt, i,
          sqlite3_errmsg(proxy_dbh));
      }
      break;
    }

    case PROXY_DB_BIND_TYPE_LONG: {
      long l;

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

      l = *((long *) data);
      res = sqlite3_bind_int(pstmt, idx, l);
      if (res != SQLITE_OK) {
        pr_trace_msg(trace_channel, 4,
          "error binding parameter %d of '%s' to LONG %ld: %s", idx, stmt, l,
          sqlite3_errmsg(proxy_dbh));
      }
      break;
    }

    case PROXY_DB_BIND_TYPE_TEXT: {
      const char *text;

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

      text = (const char *) data;
      res = sqlite3_bind_text(pstmt, idx, text, -1, NULL);
      if (res != SQLITE_OK) {
        pr_trace_msg(trace_channel, 4,
          "error binding parameter %d of '%s' to TEXT '%s': %s", idx, stmt,
          text, sqlite3_errmsg(proxy_dbh));
      }
      break;
    }

    case PROXY_DB_BIND_TYPE_NULL:
      res = sqlite3_bind_null(pstmt, idx);
      if (res != SQLITE_OK) {
        pr_trace_msg(trace_channel, 4,
          "error binding parameter %d of '%s' to NULL: %s", idx, stmt,
          sqlite3_errmsg(proxy_dbh));
      }
      break;

    default:
      pr_trace_msg(trace_channel, 2,
        "unknown/unsupported bind data type %d", type);
      errno = EINVAL;
      return -1;
  }

  return 0;
}
Exemplo n.º 27
0
MODRET copy_cpto(cmd_rec *cmd) {
  register unsigned int i;
  const char *from, *to = "";
  unsigned char *authenticated = NULL;

  if (copy_engine == FALSE) {
    return PR_DECLINED(cmd);
  }

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

  authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
  if (authenticated == NULL ||
      *authenticated == FALSE) {
    pr_response_add_err(R_530, _("Please login with USER and PASS"));

    pr_cmd_set_errno(cmd, EPERM);
    errno = EPERM;
    return PR_ERROR(cmd);
  }

  CHECK_CMD_MIN_ARGS(cmd, 3);

  from = pr_table_get(session.notes, "mod_copy.cpfr-path", NULL);
  if (from == NULL) {
    pr_response_add_err(R_503, _("Bad sequence of commands"));

    pr_cmd_set_errno(cmd, EPERM);
    errno = EPERM;
    return PR_ERROR(cmd);
  }

  /* Construct the target file name by concatenating all the parameters after
   * the "SITE CPTO", separating them with spaces.
   */
  for (i = 2; i <= cmd->argc-1; i++) {
    char *decoded_path;

    decoded_path = pr_fs_decode_path2(cmd->tmp_pool, cmd->argv[i],
      FSIO_DECODE_FL_TELL_ERRORS);
    if (decoded_path == NULL) {
      int xerrno = errno;

      pr_log_debug(DEBUG8, "'%s' failed to decode properly: %s",
        (char *) cmd->argv[i], strerror(xerrno));
      pr_response_add_err(R_550,
        _("%s: Illegal character sequence in filename"), cmd->arg);

      pr_cmd_set_errno(cmd, xerrno);
      errno = xerrno;
      return PR_ERROR(cmd);
    }

    to = pstrcat(cmd->tmp_pool, to, *to ? " " : "", decoded_path, NULL);
  }

  to = dir_canonical_vpath(cmd->tmp_pool, to);

  if (copy_paths(cmd->tmp_pool, from, to) < 0) {
    int xerrno = errno;

    pr_response_add_err(R_550, "%s: %s", (char *) cmd->argv[1],
      strerror(xerrno));

    pr_cmd_set_errno(cmd, xerrno);
    errno = xerrno;
    return PR_ERROR(cmd);
  }

  pr_response_add(R_250, "%s", _("Copy successful"));
  return PR_HANDLED(cmd);
}
Exemplo n.º 28
0
int xferlog_write(long xfertime, const char *remhost, off_t fsize, char *fname,
    char xfertype, char direction, char access_mode, char *user,
    char abort_flag, const char *action_flags) {
  const char *xfer_proto;
  char buf[LOGBUFFER_SIZE] = {'\0'}, fbuf[LOGBUFFER_SIZE] = {'\0'};
  int have_ident = FALSE, len;
  char *rfc1413_ident = NULL;
  register unsigned int i = 0;

  if (xferlogfd == -1 ||
      remhost == NULL ||
      user == NULL ||
      fname == NULL) {
    return 0;
  }

  for (i = 0; (i + 1 < sizeof(fbuf)) && fname[i] != '\0'; i++) {
    fbuf[i] = (PR_ISSPACE(fname[i]) || PR_ISCNTRL(fname[i])) ? '_' :
      fname[i];
  }
  fbuf[i] = '\0';

  rfc1413_ident = pr_table_get(session.notes, "mod_ident.rfc1413-ident", NULL);
  if (rfc1413_ident) {
    have_ident = TRUE;

    /* If the retrieved identity is "UNKNOWN", then change the string to be
     * "*", since "*" is to be logged in the xferlog, as per the doc, when
     * the authenticated user ID is not available.
     */
    if (strncmp(rfc1413_ident, "UNKNOWN", 8) == 0)
      rfc1413_ident = "*";

  } else {
    /* If an authenticated user ID is not available, log "*", as per the
     * xferlog man page/spec.
     */
    rfc1413_ident = "*";
  }

  xfer_proto = pr_session_get_protocol(0);

  len = snprintf(buf, sizeof(buf),
    "%s %ld %s %" PR_LU " %s %c %s %c %c %s %s %c %s %c\n",
      pr_strtime(time(NULL)),
      xfertime,
      remhost,
      (pr_off_t) fsize,
      fbuf,
      xfertype,
      action_flags,
      direction,
      access_mode,
      user,
      xfer_proto,
      have_ident ? '1' : '0',
      rfc1413_ident,
      abort_flag);

  buf[sizeof(buf)-1] = '\0';

  pr_log_event_generate(PR_LOG_TYPE_XFERLOG, xferlogfd, -1, buf, len);
  return write(xferlogfd, buf, len);
}
Exemplo n.º 29
0
const char *pr_session_get_disconnect_reason(char **details) {
  const char *reason_str = NULL;

  switch (session.disconnect_reason) {
    case PR_SESS_DISCONNECT_UNSPECIFIED:
      reason_str = "Unknown/unspecified";
      break;

    case PR_SESS_DISCONNECT_CLIENT_QUIT:
      reason_str = "Quit";
      break;

    case PR_SESS_DISCONNECT_CLIENT_EOF:
      reason_str = "Read EOF from client";
      break;

    case PR_SESS_DISCONNECT_SESSION_INIT_FAILED:
      reason_str = "Session initialized failed";
      break;

    case PR_SESS_DISCONNECT_SIGNAL:
      reason_str = "Terminated by signal";
      break;

    case PR_SESS_DISCONNECT_NOMEM:
      reason_str = "Low memory";
      break;

    case PR_SESS_DISCONNECT_SERVER_SHUTDOWN:
      reason_str = "Server shutting down";
      break;

    case PR_SESS_DISCONNECT_TIMEOUT:
      reason_str = "Timeout exceeded";
      break;

    case PR_SESS_DISCONNECT_BANNED:
      reason_str = "Banned";
      break;

    case PR_SESS_DISCONNECT_CONFIG_ACL:
      reason_str = "Configured policy";
      break;

    case PR_SESS_DISCONNECT_MODULE_ACL:
      reason_str = "Module-specific policy";
      break;

    case PR_SESS_DISCONNECT_BAD_CONFIG:
      reason_str = "Server misconfiguration";
      break;

    case PR_SESS_DISCONNECT_BY_APPLICATION:
      reason_str = "Application error";
      break;
  }

  if (details != NULL) {
    *details = pr_table_get(session.notes, "core.disconnect-details", NULL);
  }

  return reason_str;
}