Beispiel #1
0
END_TEST

START_TEST (add_config_param_set_test) {
  xaset_t *set = NULL;
  const char *name = NULL;
  config_rec *c = NULL;

  name = "foo";

  c = add_config_param_set(NULL, name, 0);
  fail_unless(c == NULL, "Failed to handle null set argument");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %d (%s)",
    errno, strerror(errno));

  c = add_config_param_set(&set, name, 0);
  fail_unless(c != NULL, "Failed to add config '%s' to set: %s", name,
    strerror(errno));
  fail_unless(c->config_type == CONF_PARAM, "Expected config_type %d, got %d",
    CONF_PARAM, c->config_type);
  fail_unless(c->argc == 0, "Expected argc 0, got %d", c->argc);

  c = add_config_param_set(&set, name, 2, "bar", "baz");
  fail_unless(c != NULL, "Failed to add config '%s' to set: %s", name,
    strerror(errno));
  fail_unless(c->config_type == CONF_PARAM, "Expected config_type %d, got %d",
    CONF_PARAM, c->config_type);
  fail_unless(c->argc == 2, "Expected argc 2, got %d", c->argc);
  fail_unless(strcmp("bar", (char *) c->argv[0]) == 0,
    "Expected argv[0] to be 'bar', got '%s'", (char *) c->argv[0]);
  fail_unless(strcmp("baz", (char *) c->argv[1]) == 0,
    "Expected argv[1] to be 'baz', got '%s'", (char *) c->argv[1]);
  fail_unless(c->argv[2] == NULL, "Expected argv[2] to be null");
}
Beispiel #2
0
END_TEST

START_TEST (filter_allow_path_test) {
  int res;
  config_rec *c;
  pr_regex_t *allow_pre, *deny_pre;
  xaset_t *set = NULL;
  const char *path = NULL;

  res = pr_filter_allow_path(NULL, NULL);
  fail_unless(res < 0, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

  mark_point();
  c = add_config_param_set(&set, "test", 1, "test");
  fail_if(c == NULL, "Failed to add config param: %s", strerror(errno));

  path = "/foo/bar";
  res = pr_filter_allow_path(set, path);
  fail_unless(res == 0, "Failed to allow path '%s' with no configured filters",
    path);

  /* First, let's add a PathDenyFilter. */
  deny_pre = pr_regexp_alloc(NULL);
  res = pr_regexp_compile(deny_pre, "/bar$", 0);
  fail_unless(res == 0, "Error compiling deny filter");

  c = add_config_param_set(&set, "PathDenyFilter", 1, deny_pre);
  fail_if(c == NULL, "Failed to add config param: %s", strerror(errno));

  mark_point();
  res = pr_filter_allow_path(set, path);
  fail_unless(res == PR_FILTER_ERR_FAILS_DENY_FILTER,
    "Failed to reject path '%s' with matching PathDenyFilter", path);

  mark_point();
  path = "/foo/baz";
  res = pr_filter_allow_path(set, path);
  fail_unless(res == 0,
    "Failed to allow path '%s' with non-matching PathDenyFilter", path);

  /* Now, let's add a PathAllowFilter. */
  allow_pre = pr_regexp_alloc(NULL);
  res = pr_regexp_compile(allow_pre, "/baz$", 0);
  fail_unless(res == 0, "Error compiling allow filter");

  c = add_config_param_set(&set, "PathAllowFilter", 1, allow_pre);
  fail_if(c == NULL, "Failed to add config param: %s", strerror(errno));

  mark_point();
  path = "/foo/quxx";
  res = pr_filter_allow_path(set, path);
  fail_unless(res == PR_FILTER_ERR_FAILS_ALLOW_FILTER,
    "Failed to allow path '%s' with matching PathAllowFilter", path);
}
Beispiel #3
0
END_TEST

START_TEST (config_add_config_test) {
  int res;
  const char *name = NULL;
  config_rec *c = NULL;
  server_rec *s = NULL;

  s = pr_parser_server_ctxt_open("127.0.0.1");
  fail_unless(s != NULL, "Failed to open server context: %s", strerror(errno));

  name = "foo";

  mark_point();
  c = add_config(NULL, name);
  fail_unless(c != NULL, "Failed to add config '%s': %s", name,
    strerror(errno));
  fail_unless(c->config_type == 0, "Expected config_type 0, got %d",
    c->config_type);

  mark_point();
  pr_config_dump(NULL, s->conf, NULL);

  c = add_config_param_set(&(c->subset), "bar", 1, "baz");

  mark_point();
  pr_config_dump(NULL, s->conf, NULL);

  mark_point();
  res = remove_config(s->conf, name, FALSE);
  fail_unless(res > 0, "Failed to remove config '%s': %s", name,
    strerror(errno));
}
Beispiel #4
0
MODRET pw_getpwnam(cmd_rec *cmd) {
  struct passwd *pw;
  const char *name;

  name = cmd->argv[0];
  if (persistent_passwd) {
    pw = p_getpwnam(name);

  } else {
    pw = getpwnam(name);
  }

  if (auth_unix_opts & AUTH_UNIX_OPT_MAGIC_TOKEN_CHROOT) {
    char *home_dir, *ptr;

    /* Here is where we do the "magic token" chroot monstrosity inflicted
     * on the world by wu-ftpd.
     *
     * If the magic token '/./' appears in the user's home directory, the
     * directory portion before the token is the directory to use for
     * the chroot; the directory portion after the token is the directory
     * to use for the initial chdir.
     */

    home_dir = pstrdup(cmd->tmp_pool, pw->pw_dir);

    /* We iterate through the home directory string since it is possible
     * for the '.' character to appear without it being part of the magic
     * token.
     */
    ptr = strchr(home_dir, '.');
    while (ptr != NULL) {
      pr_signals_handle();

      /* If we're at the start of the home directory string, stop looking:
       * this home directory is not really valid anyway.
       */
      if (ptr == home_dir) {
        break;
      }

      /* Back up one character. */
      ptr--;

      /* If we're at the start of the home directory now, stop looking:
       * this home directory cannot contain a valid magic token.  I.e.
       *
       * /./home/foo
       *
       * cannot be valid, as there is no directory portion before the
       * token.
       */
      if (ptr == home_dir) {
        break;
      }

      if (strncmp(ptr, "/./", 3) == 0) {
        char *default_chdir;
        config_rec *c;

        *ptr = '\0';
        default_chdir = pstrdup(cmd->tmp_pool, ptr + 2);

        /* In order to make sure that this user is chrooted to this
         * directory, we remove all DefaultRoot directives and add a new
         * one.  Same for the DefaultChdir directive.
         */

        (void) remove_config(main_server->conf, "DefaultRoot", FALSE);
        c = add_config_param_set(&main_server->conf, "DefaultRoot", 1, NULL);
        c->argv[0] = pstrdup(c->pool, home_dir);

        (void) remove_config(main_server->conf, "DefaultChdir", FALSE);
        c = add_config_param_set(&main_server->conf, "DefaultChdir", 1, NULL);
        c->argv[0] = pstrdup(c->pool, default_chdir);

        pr_log_debug(DEBUG9, "AuthUnixOption magicTokenChroot: "
          "found magic token in '%s', using 'DefaultRoot %s' and "
          "'DefaultChdir %s'", pw->pw_dir, home_dir, default_chdir);

        /* We need to use a long-lived memory pool for overwriting the
         * normal home directory.
         */
        pw->pw_dir = pstrdup(session.pool, home_dir);

        break;
      }

      ptr = strchr(ptr + 2, '.');
    }
  }

  return pw ? mod_create_data(cmd, pw) : PR_DECLINED(cmd);
}
Beispiel #5
0
END_TEST

START_TEST (get_param_ptr_test) {
  void *res;
  int count;
  xaset_t *set = NULL;
  config_rec *c;
  const char *name = NULL;

  res = get_param_ptr(NULL, NULL, FALSE);
  fail_unless(res == NULL, "Failed to handle null arguments");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  mark_point();

  name = "foo";
  c = add_config_param_set(&set, name, 1, "bar");
  fail_unless(c != NULL, "Failed to add config '%s': %s", name,
    strerror(errno));

  name = "bar";
  res = get_param_ptr(set, name, FALSE);
  fail_unless(res == NULL, "Failed to handle null arguments");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  mark_point();

  /* We expect to find "foo", but a 'next' should be empty. Note that we
   * need to reset the get_param_ptr tree.
   */
  get_param_ptr(NULL, NULL, FALSE);

  name = "foo";
  res = get_param_ptr(set, name, FALSE);
  fail_unless(res != NULL, "Failed to find config '%s': %s", name,
    strerror(errno));

  mark_point();

  res = get_param_ptr_next(name, FALSE);
  fail_unless(res == NULL, "Found next config unexpectedly");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  /* Now add another config, find "foo" again; this time, a 'next' should
   * NOT be empty; it should find the 2nd config we added.
   */

  name = "foo2";
  c = add_config_param_set(&set, name, 1, "baz");
  fail_unless(c != NULL, "Failed to add config '%s': %s", name,
    strerror(errno));

  get_param_ptr(NULL, NULL, FALSE);

  name = NULL;
  res = get_param_ptr(set, name, FALSE);
  fail_unless(res != NULL, "Failed to find any config: %s", strerror(errno));

  mark_point();

  res = get_param_ptr_next(name, FALSE);
  fail_unless(res != NULL, "Expected to find another config");

  mark_point();

  name = "foo";
  count = remove_config(set, name, FALSE);
  fail_unless(count > 0, "Failed to remove config '%s': %s", name,
    strerror(errno));

  mark_point();

  res = get_param_ptr(set, name, FALSE);
  fail_unless(res == NULL, "Found config '%s' unexpectedly", name);
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));
}
Beispiel #6
0
END_TEST

START_TEST (find_config2_test) {
  int res;
  config_rec *c;
  xaset_t *set = NULL;
  const char *name;
  unsigned long flags = 0;

  c = find_config2(NULL, -1, NULL, FALSE, flags);
  fail_unless(c == NULL, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %d (%s)",
    errno, strerror(errno));

  mark_point();

  name = "foo";
  c = add_config_param_set(&set, name, 0);
  fail_unless(c != NULL, "Failed to add config '%s': %s", name,
    strerror(errno));

  name = "bar";
  c = find_config2(set, -1, name, FALSE, flags);
  fail_unless(c == NULL, "Failed to handle null arguments");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  mark_point();

  /* We expect to find "foo", but a 'next' should be empty. */
  name = "foo";
  c = find_config2(set, -1, name, FALSE, flags);
  fail_unless(c != NULL, "Failed to find config '%s': %s", name,
    strerror(errno));

  mark_point();

  c = find_config_next2(c, c->next, -1, name, FALSE, flags);
  fail_unless(c == NULL, "Found next config unexpectedly");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  /* Now add another config, find "foo" again; this time, a 'next' should
   * NOT be empty; it should find the 2nd config we added.
   */

  name = "foo2";
  c = add_config_param_set(&set, name, 0);
  fail_unless(c != NULL, "Failed to add config '%s': %s", name,
    strerror(errno));

  name = NULL;
  c = find_config2(set, -1, name, FALSE, flags);
  fail_unless(c != NULL, "Failed to find any config: %s", strerror(errno));

  mark_point();

  c = find_config_next2(c, c->next, -1, name, FALSE, flags);
  fail_unless(c != NULL, "Expected to find another config");

  mark_point();

  name = "foo";
  res = remove_config(set, name, FALSE);
  fail_unless(res > 0, "Failed to remove config '%s': %s", name,
    strerror(errno));

  mark_point();

  c = find_config2(set, -1, name, FALSE, flags);
  fail_unless(c == NULL, "Found config '%s' unexpectedly", name);
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));
}
Beispiel #7
0
END_TEST

START_TEST (config_merge_down_test) {
  xaset_t *set;
  config_rec *c, *src, *dst;
  const char *name;

  mark_point();
  pr_config_merge_down(NULL, FALSE);

  mark_point();
  set = xaset_create(p, NULL);
  pr_config_merge_down(set, FALSE);

  name = "foo";
  c = add_config_param_set(&set, name, 0);

  mark_point();
  pr_config_merge_down(set, FALSE);

  name = "bar";
  c = add_config_param_set(&set, name, 1, "baz");
  c->flags |= CF_MERGEDOWN;

  mark_point();
  pr_config_merge_down(set, FALSE);

  name = "BAZ";
  c = add_config_param_set(&set, name, 2, "quxx", "Quzz");
  c->flags |= CF_MERGEDOWN_MULTI;

  mark_point();
  pr_config_merge_down(set, FALSE);

  /* Add a config to the subsets, with the same name and same args. */
  name = "<Anonymous>";
  src = add_config_param_set(&set, name, 0);
  src->config_type = CONF_ANON;

  mark_point();
  pr_config_merge_down(set, FALSE);

  name = "<Directory>";
  dst = add_config_param_set(&set, name, 1, "/baz");
  dst->config_type = CONF_DIR;

  name = "foo";
  c = add_config_param_set(&(src->subset), name, 1, "alef");
  c->flags |= CF_MERGEDOWN;

  c = add_config_param_set(&(dst->subset), name, 1, "alef");
  c->flags |= CF_MERGEDOWN;

  mark_point();
  pr_config_merge_down(set, FALSE);

  /* Add a config to the subsets, with the same name and diff args. */
  name = "alef";
  c = add_config_param_set(&(src->subset), name, 1, "alef");
  c->flags |= CF_MERGEDOWN;

  c = add_config_param_set(&(dst->subset), name, 2, "bet", "vet");
  c->flags |= CF_MERGEDOWN;

  c = add_config_param_set(&(src->subset), "Bet", 3, "1", "2", "3");
  c->config_type = CONF_LIMIT;
  c->flags |= CF_MERGEDOWN;

  mark_point();
  pr_config_merge_down(set, FALSE);
}
Beispiel #8
0
static int sftppam_driver_open(sftp_kbdint_driver_t *driver, const char *user) {
  int res;
  config_rec *c;

  /* XXX Should we pay attention to AuthOrder here?  I.e. if AuthOrder
   * does not include mod_sftp_pam or mod_auth_pam, should we fail to
   * open this driver, since the AuthOrder indicates that no PAM check is
   * desired?  For this to work, AuthOrder needs to have been processed
   * prior to this callback being invoked...
   */

  /* Figure out our default return style: whether or not PAM should allow
   * other auth modules a shot at this user or not is controlled by adding
   * '*' to a module name in the AuthOrder directive.  By default, auth
   * modules are not authoritative, and allow other auth modules a chance at
   * authenticating the user.  This is not the most secure configuration, but
   * it allows things like AuthUserFile to work "out of the box".
   */
  if (sftppam_authtab[0].auth_flags & PR_AUTH_FL_REQUIRED) {
    sftppam_authoritative = TRUE;
  }

  sftppam_userlen = strlen(user) + 1;
  if (sftppam_userlen > (PAM_MAX_MSG_SIZE + 1)) {
    sftppam_userlen = PAM_MAX_MSG_SIZE + 1;
  }

#ifdef MAXLOGNAME
  /* Some platforms' PAM libraries do not handle login strings that exceed
   * this length.
   */
  if (sftppam_userlen > MAXLOGNAME) {
    pr_log_pri(PR_LOG_NOTICE,
      "PAM(%s): Name exceeds maximum login length (%u)", user, MAXLOGNAME);
    pr_trace_msg(trace_channel, 1,
      "user name '%s' exceeds maximum login length %u, declining", user,
      MAXLOGNAME);
    errno = EPERM;
    return -1;
  }
#endif

  sftppam_user = malloc(sftppam_userlen);
  if (sftppam_user == NULL) {
    pr_log_pri(PR_LOG_ALERT, MOD_SFTP_PAM_VERSION ": Out of memory!");
    exit(1);
  }

  memset(sftppam_user, '\0', sftppam_userlen);
  sstrncpy(sftppam_user, user, sftppam_userlen);

  c = find_config(main_server->conf, CONF_PARAM, "SFTPPAMOptions", FALSE);
  while (c != NULL) {
    unsigned long opts;

    pr_signals_handle();

    opts = *((unsigned long *) c->argv[0]);
    sftppam_opts |= opts;

    c = find_config_next(c, c->next, CONF_PARAM, "SFTPPAMOptions", FALSE);
  }
 
#ifdef SOLARIS2
  /* For Solaris environments, the TTY environment will always be set,
   * in order to workaround a bug (Solaris Bug ID 4250887) where
   * pam_open_session() will crash unless both PAM_RHOST and PAM_TTY are
   * set, and the PAM_TTY setting is at least greater than the length of
   * the string "/dev/".
   */
  sftppam_opts &= ~SFTP_PAM_OPT_NO_TTY;
#endif /* SOLARIS2 */
 
  pr_signals_block();
  PRIVS_ROOT

  res = pam_start(sftppam_service, sftppam_user, &sftppam_conv, &sftppam_pamh);
  if (res != PAM_SUCCESS) {
    PRIVS_RELINQUISH
    pr_signals_unblock();

    free(sftppam_user);
    sftppam_user = NULL;
    sftppam_userlen = 0;

    switch (res) {
      case PAM_SYSTEM_ERR:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_PAM_VERSION,
          "error starting PAM service: %s", strerror(errno));
        break;

      case PAM_BUF_ERR:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_PAM_VERSION,
          "error starting PAM service: Memory buffer error");
        break;
    }

    return -1;
  }

  pam_set_item(sftppam_pamh, PAM_RUSER, sftppam_user);
  pam_set_item(sftppam_pamh, PAM_RHOST, session.c->remote_name);

  if (!(sftppam_opts & SFTP_PAM_OPT_NO_TTY)) {
    memset(sftppam_tty, '\0', sizeof(sftppam_tty));
    snprintf(sftppam_tty, sizeof(sftppam_tty), "/dev/ftpd%02lu",
      (unsigned long) (session.pid ? session.pid : getpid()));
    sftppam_tty[sizeof(sftppam_tty)-1] = '\0';

    pr_trace_msg(trace_channel, 9, "setting PAM_TTY to '%s'", sftppam_tty);
    pam_set_item(sftppam_pamh, PAM_TTY, sftppam_tty);
  }

  PRIVS_RELINQUISH
  pr_signals_unblock();

  /* We need to disable mod_auth_pam, since both mod_auth_pam and us want
   * to talk to the PAM API, just in different fashions.
   */

  c = add_config_param_set(&(main_server->conf), "AuthPAM", 1, NULL);
  c->argv[0] = palloc(c->pool, sizeof(unsigned char));
  *((unsigned char *) c->argv[0]) = FALSE;

  if (pr_auth_remove_auth_only_module("mod_auth_pam.c") < 0) {
    if (errno != ENOENT) {
      pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_PAM_VERSION
        ": error removing 'mod_auth_pam.c' from the auth-only module list: %s",
        strerror(errno));
    }
  }

  if (pr_auth_add_auth_only_module("mod_sftp_pam.c") < 0) {
    if (errno != EEXIST) {
      pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_PAM_VERSION
        ": error adding 'mod_sftp_pam.c' to the auth-only module list: %s",
        strerror(errno));
    }
  }

  sftppam_handle_auth = TRUE;

  driver->driver_pool = make_sub_pool(permanent_pool);
  pr_pool_tag(driver->driver_pool, "PAM keyboard-interactive driver pool");

  return 0;
}