Exemple #1
0
static int match_version(pool *p, const char *pattern_str, char **error) {
#ifdef PR_USE_REGEX
  pr_regex_t *pre;
  int res;

  pre = pr_regexp_alloc(&ifversion_module);

  res = pr_regexp_compile(pre, pattern_str, REG_EXTENDED|REG_NOSUB|REG_ICASE);
  if (res != 0) {
    char errstr[256];

    memset(errstr, '\0', sizeof(errstr));
    pr_regexp_error(res, pre, errstr, sizeof(errstr)-1);

    pr_regexp_free(NULL, pre);
    *error = pstrcat(p, "unable to compile pattern '", pattern_str, "': ",
      errstr, NULL);

    return 0;
  }

  res = pr_regexp_exec(pre, pr_version_get_str(), 0, NULL, 0, 0, 0);
  if (res != 0) {
    *error = pstrcat(p, "server version '", pr_version_get_str(),
      "' failed to match pattern '", pattern_str, "'", NULL);
  }

  pr_regexp_free(NULL, pre);
  return (res == 0 ? 1 : 0);

#else
  *error = pstrdup(p, "system does not support POSIX regular expressions");
  return 0;
#endif /* regex support */
}
Exemple #2
0
END_TEST

START_TEST (regexp_set_limits_test) {
  int res;
  pr_regex_t *pre = NULL;
  const char *pattern, *str;

  res = pr_regexp_set_limits(0, 0);
  fail_unless(res == 0, "Failed to set limits: %s", strerror(errno));

  /* Set the limits, and compile/execute a regex. */
  res = pr_regexp_set_limits(1, 1);
  fail_unless(res == 0, "Failed to set limits: %s", strerror(errno));

  pre = pr_regexp_alloc(NULL);

  pattern = "^foo";
  res = pr_regexp_compile(pre, pattern, REG_ICASE);
  fail_unless(res == 0, "Failed to compile regex pattern '%s'", pattern);

  str = "fooBAR";
  (void) pr_regexp_exec(pre, str, 0, NULL, 0, 0, 0);

  pr_regexp_free(NULL, pre);
}
Exemple #3
0
static int af_allow_grent(struct group *grp) {
  if (!af_group_file) {
    errno = EPERM;
    return -1;
  }

  /* Check that the grent is within the ID restrictions (if present). */
  if (af_group_file->af_restricted_ids) {

    if (grp->gr_gid < af_group_file->af_min_id.gid) {
      pr_log_debug(DEBUG3, MOD_AUTH_FILE_VERSION ": skipping group '%s': "
        "GID %lu below the minimum allowed (%lu)", grp->gr_name,
        (unsigned long) grp->gr_gid,
        (unsigned long) af_group_file->af_min_id.gid);
      errno = EINVAL;
      return -1;
    }

    if (grp->gr_gid > af_group_file->af_max_id.gid) {
      pr_log_debug(DEBUG3, MOD_AUTH_FILE_VERSION ": skipping group '%s': "
        "GID %lu above the maximum allowed (%lu)", grp->gr_name,
        (unsigned long) grp->gr_gid,
        (unsigned long) af_group_file->af_max_id.gid);
      errno = EINVAL;
      return -1;
    }
  }

#ifdef PR_USE_REGEX
  /* Check if the grent has an acceptable name. */
  if (af_group_file->af_restricted_names) {
    int res;

    res = pr_regexp_exec(af_group_file->af_name_regex, grp->gr_name, 0,
      NULL, 0, 0, 0);

    if ((res != 0 && !af_group_file->af_name_regex_inverted) ||
        (res == 0 && af_group_file->af_name_regex_inverted)) {
      pr_log_debug(DEBUG3, MOD_AUTH_FILE_VERSION ": skipping group '%s': "
        "name '%s' does not meet allowed filter '%s'", grp->gr_name,
        grp->gr_name, af_group_file->af_name_filter);
      errno = EINVAL;
      return -1;
    }
  }
#endif /* regex support */

  return 0;
}
Exemple #4
0
END_TEST

START_TEST (regexp_exec_test) {
  pr_regex_t *pre = NULL;
  int res;
  char *pattern, *str;

  res = pr_regexp_exec(NULL, NULL, 0, NULL, 0, 0, 0);
  fail_unless(res < 0, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  pre = pr_regexp_alloc(NULL);

  pattern = "^foo";
  res = pr_regexp_compile(pre, pattern, 0);
  fail_unless(res == 0, "Failed to compile regex pattern '%s'", pattern);

  res = pr_regexp_exec(pre, NULL, 0, NULL, 0, 0, 0);
  fail_unless(res != 0, "Failed to handle null string");

  str = "bar";
  res = pr_regexp_exec(pre, str, 0, NULL, 0, 0, 0);
  fail_unless(res != 0, "Matched string unexpectedly");

  str = "foobar";
  res = pr_regexp_exec(pre, str, 0, NULL, 0, 0, 0);
  fail_unless(res == 0, "Failed to match string");

  pr_regexp_free(NULL, pre);

  pre = pr_regexp_alloc(NULL);

  pattern = "^foo";
  res = pr_regexp_compile_posix(pre, pattern, REG_ICASE);
  fail_unless(res == 0, "Failed to compile regex pattern '%s'", pattern);

  res = pr_regexp_exec(pre, NULL, 0, NULL, 0, 0, 0);
  fail_unless(res != 0, "Failed to handle null string");

  str = "BAR";
  res = pr_regexp_exec(pre, str, 0, NULL, 0, 0, 0);
  fail_unless(res != 0, "Matched string unexpectedly");

  str = "FOOBAR";
  res = pr_regexp_exec(pre, str, 0, NULL, 0, 0, 0);
  fail_unless(res == 0, "Failed to match string");

  pr_regexp_free(NULL, pre);
}
static int forward_dst_filter(pool *p, const char *hostport) {
#ifdef PR_USE_REGEX
  config_rec *c;
  pr_regex_t *pre;
  int negated = FALSE, res;

  c = find_config(main_server->conf, CONF_PARAM, "ProxyForwardTo", FALSE);
  if (c == NULL) {
    return 0;
  }

  pre = c->argv[0];
  negated = *((int *) c->argv[1]);

  res = pr_regexp_exec(pre, hostport, 0, NULL, 0, 0, 0);
  if (res == 0) {
    /* Pattern matched */
    if (negated == TRUE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "host/port '%.100s' matched ProxyForwardTo !%s, rejecting",
        hostport, pr_regexp_get_pattern(pre));

      errno = EPERM;
      return -1;
    }

  } else {
    /* Pattern NOT matched */
    if (negated == FALSE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "host/port '%.100s' did not match ProxyForwardTo %s, rejecting",
        hostport, pr_regexp_get_pattern(pre));
      errno = EPERM;
      return -1;
    }
  }
#endif /* PR_USE_REGEX */
  return 0;
}
Exemple #6
0
MODRET site_chgrp(cmd_rec *cmd) {
  int res;
  gid_t gid;
  char *path = NULL, *tmp = NULL, *arg = "";
  register unsigned int i = 0;
#ifdef PR_USE_REGEX
  pr_regex_t *pre;
#endif

  if (cmd->argc < 3) {
    pr_response_add_err(R_500, _("'SITE %s' not understood"),
      _get_full_cmd(cmd));
    return NULL;
  }

  /* Construct the target file name by concatenating all the parameters after
   * the mode, separating them with spaces.
   */
  for (i = 2; i <= cmd->argc-1; i++)
    arg = pstrcat(cmd->tmp_pool, arg, *arg ? " " : "",
      pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL);

#ifdef PR_USE_REGEX
  pre = get_param_ptr(CURRENT_CONF, "PathAllowFilter", FALSE);
  if (pre != NULL &&
      pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) != 0) {
    pr_log_debug(DEBUG2, "'%s %s' denied by PathAllowFilter", cmd->argv[0],
      arg);
    pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg);
    return PR_ERROR(cmd);
  }

  pre = get_param_ptr(CURRENT_CONF, "PathDenyFilter", FALSE);
  if (pre != NULL &&
      pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) == 0) {
    pr_log_debug(DEBUG2, "'%s %s' denied by PathDenyFilter", cmd->argv[0],
      arg);
    pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg);
    return PR_ERROR(cmd);
  }
#endif

  path = dir_realpath(cmd->tmp_pool, arg);

  if (!path) {
    pr_response_add_err(R_550, "%s: %s", arg, strerror(errno));
    return PR_ERROR(cmd);
  }

  /* Map the given group argument, if a string, to a GID.  If already a
   * number, pass through as is.
   */
  gid = strtoul(cmd->argv[1], &tmp, 10);

  if (tmp && *tmp) {

    /* Try the parameter as a group name. */
    gid = pr_auth_name2gid(cmd->tmp_pool, cmd->argv[1]);
    if (gid == (gid_t) -1) {
      pr_log_debug(DEBUG9,
        "SITE CHGRP: Unable to resolve group name '%s' to GID", cmd->argv[1]);
      pr_response_add_err(R_550, "%s: %s", arg, strerror(EINVAL));
      return PR_ERROR(cmd);
    }
  }

  res = core_chgrp(cmd, path, (uid_t) -1, gid);
  if (res < 0) {
    int xerrno = errno;

    (void) pr_trace_msg("fileperms", 1, "%s, user '%s' (UID %lu, GID %lu): "
      "error chown'ing '%s' to GID %lu: %s", cmd->argv[0], session.user,
      (unsigned long) session.uid, (unsigned long) session.gid,
      path, (unsigned long) gid, strerror(xerrno));

    pr_response_add_err(R_550, "%s: %s", arg, strerror(xerrno));

    errno = xerrno;
    return PR_ERROR(cmd);

  } else {
    pr_response_add(R_200, _("SITE %s command successful"), cmd->argv[0]);
  }

  return PR_HANDLED(cmd);
}
Exemple #7
0
MODRET site_chmod(cmd_rec *cmd) {
  int res;
  mode_t mode = 0;
  char *dir, *endp, *tmp, *arg = "";
  register unsigned int i = 0;
#ifdef PR_USE_REGEX
  pr_regex_t *pre;
#endif

  if (cmd->argc < 3) {
    pr_response_add_err(R_500, _("'SITE %s' not understood"),
      _get_full_cmd(cmd));
    return NULL;
  }

  /* Construct the target file name by concatenating all the parameters after
   * the mode, separating them with spaces.
   */
  for (i = 2; i <= cmd->argc-1; i++)
    arg = pstrcat(cmd->tmp_pool, arg, *arg ? " " : "",
      pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL);

#ifdef PR_USE_REGEX
  pre = get_param_ptr(CURRENT_CONF, "PathAllowFilter", FALSE);
  if (pre != NULL &&
      pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) != 0) {
    pr_log_debug(DEBUG2, "'%s %s %s' denied by PathAllowFilter", cmd->argv[0],
      cmd->argv[1], arg);
    pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg);
    return PR_ERROR(cmd);
  }

  pre = get_param_ptr(CURRENT_CONF, "PathDenyFilter", FALSE);
  if (pre != NULL &&
      pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) == 0) {
    pr_log_debug(DEBUG2, "'%s %s %s' denied by PathDenyFilter", cmd->argv[0],
      cmd->argv[1], arg);
    pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg);
    return PR_ERROR(cmd);
  }
#endif

  dir = dir_realpath(cmd->tmp_pool, arg);

  if (!dir) {
    pr_response_add_err(R_550, "%s: %s", arg, strerror(errno));
    return PR_ERROR(cmd);
  }

  /* If the first character isn't '0', prepend it and attempt conversion.
   * This will fail if the chmod is a symbolic, but takes care of the
   * case where an octal number is sent without the leading '0'.
   */

  if (cmd->argv[1][0] != '0') {
    tmp = pstrcat(cmd->tmp_pool, "0", cmd->argv[1], NULL);

  } else {
    tmp = cmd->argv[1];
  }

  mode = strtol(tmp,&endp,0);
  if (endp && *endp) {
    /* It's not an absolute number, try symbolic */
    char *cp = cmd->argv[1];
    int mask = 0, mode_op = 0, curmode = 0, curumask = umask(0);
    int invalid = 0;
    char *who, *how, *what;
    struct stat st;

    umask(curumask);
    mode = 0;

    if (pr_fsio_stat(dir, &st) != -1)
      curmode = st.st_mode;

    while (TRUE) {
      who = pstrdup(cmd->tmp_pool, cp);

      tmp = strpbrk(who, "+-=");
      if (tmp != NULL) {
        how = pstrdup(cmd->tmp_pool, tmp);
        if (*how != '=')
          mode = curmode;

        *tmp = '\0';

      } else {
        invalid++;
        break;
      }

      tmp = strpbrk(how, "rwxXstugo");
      if (tmp != NULL) {
        what = pstrdup(cmd->tmp_pool, tmp);
        *tmp = '\0';

      } else {
        invalid++;
        break;
      }

      cp = what;
      while (cp) {
        switch (*who) {
          case 'u':
            mask = 0077;
            break;

          case 'g':
            mask = 0707;
            break;

          case 'o':
            mask = 0770;
            break;

          case 'a':
            mask = 0000;
            break;

          case '\0':
            mask = curumask;
            break;

          default:
            invalid++;
            break;
        }

        if (invalid)
          break;

        switch (*how) {
          case '+':
          case '-':
          case '=':
            break;

          default:
            invalid++;
        }

        if (invalid)
          break;

        switch (*cp) {
          case 'r':
            mode_op |= (S_IRUSR|S_IRGRP|S_IROTH);
            break;

          case 'w':
            mode_op |= (S_IWUSR|S_IWGRP|S_IWOTH);
            break;
          case 'x':
            mode_op |= (S_IXUSR|S_IXGRP|S_IXOTH);
            break;

          /* 'X' not implemented */
          case 's':
            /* setuid */
            mode_op |= S_ISUID;
            break;

          case 't':
            /* sticky */
            mode_op |= S_ISVTX;
            break;

          case 'o':
            mode_op |= curmode & S_IRWXO;
            mode_op |= (curmode & S_IRWXO) << 3;
            mode_op |= (curmode & S_IRWXO) << 6;
            break;

          case 'g':
            mode_op |= (curmode & S_IRWXG) >> 3;
            mode_op |= curmode & S_IRWXG;
            mode_op |= (curmode & S_IRWXG) << 3;
            break;

          case 'u':
            mode_op |= (curmode & S_IRWXO) >> 6;
            mode_op |= (curmode & S_IRWXO) >> 3;
            mode_op |= curmode & S_IRWXU;
            break;

          case '\0':
            /* Apply the mode and move on */
            switch (*how) {
              case '+':
              case '=':
                mode |= (mode_op & ~mask);
                break;

              case '-':
                mode &= ~(mode_op & ~mask);
                break;
            }

            mode_op = 0;
            if (*who && *(who+1)) {
              who++;
              cp = what;
              continue;

            } else
              cp = NULL;

            break;

          default:
            invalid++;
        }

        if (invalid)
          break;

        if (cp)
          cp++;
      }
      break;
    }

    if (invalid) {
      pr_response_add_err(R_550, _("'%s': invalid mode"), cmd->argv[1]);
      return PR_ERROR(cmd);
    }
  }
Exemple #8
0
static int af_allow_pwent(struct passwd *pwd) {
  if (!af_user_file) {
    errno = EPERM;
    return -1;
  }

  /* Check that the pwent is within the ID restrictions (if present). */
  if (af_user_file->af_restricted_ids) {

    if (pwd->pw_uid < af_user_file->af_min_id.uid) {
      pr_log_debug(DEBUG3, MOD_AUTH_FILE_VERSION ": skipping user '%s': "
        "UID %lu below the minimum allowed (%lu)", pwd->pw_name,
        (unsigned long) pwd->pw_uid,
        (unsigned long) af_user_file->af_min_id.uid);
      errno = EINVAL;
      return -1;
    }

    if (pwd->pw_uid > af_user_file->af_max_id.gid) {
      pr_log_debug(DEBUG3, MOD_AUTH_FILE_VERSION ": skipping user '%s': "
        "UID %lu above the maximum allowed (%lu)", pwd->pw_name,
        (unsigned long) pwd->pw_uid,
        (unsigned long) af_user_file->af_max_id.uid);
      errno = EINVAL;
      return -1;
    }
  }

#ifdef PR_USE_REGEX
  /* Check if the pwent has an acceptable name. */
  if (af_user_file->af_restricted_names) {
    int res;

    res = pr_regexp_exec(af_user_file->af_name_regex, pwd->pw_name, 0, NULL,
      0, 0, 0);

    if ((res != 0 && !af_user_file->af_name_regex_inverted) ||
        (res == 0 && af_user_file->af_name_regex_inverted)) {
      pr_log_debug(DEBUG3, MOD_AUTH_FILE_VERSION ": skipping user '%s': "
        "name '%s' does not meet allowed filter '%s'", pwd->pw_name,
        pwd->pw_name, af_user_file->af_name_filter);
      errno = EINVAL;
      return -1;
    }
  }

  /* Check if the pwent has an acceptable home directory. */
  if (af_user_file->af_restricted_homes) {
    int res;

    res = pr_regexp_exec(af_user_file->af_home_regex, pwd->pw_dir, 0, NULL,
      0, 0, 0);

    if ((res != 0 && !af_user_file->af_home_regex_inverted) ||
        (res == 0 && af_user_file->af_home_regex_inverted)) {
      pr_log_debug(DEBUG3, MOD_AUTH_FILE_VERSION ": skipping user '%s': "
        "home '%s' does not meet allowed filter '%s'", pwd->pw_name,
        pwd->pw_dir, af_user_file->af_home_filter);
      errno = EINVAL;
      return -1;
    }
  }
#endif /* regex support */

  return 0;
}
Exemple #9
0
static int check_geoip_filters(geoip_policy_e policy) {
  int matched_allow_filter = -1, allow_conn = 0;
#if PR_USE_REGEX
  config_rec *c;

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPAllowFilter", FALSE);
  while (c) {
    int filter_id, res;
    pr_regex_t *filter_re;
    const char *filter_name, *filter_pattern, *filter_value;

    pr_signals_handle();

    if (matched_allow_filter == -1) {
      matched_allow_filter = FALSE;
    }

    filter_id = *((int *) c->argv[0]);
    filter_pattern = c->argv[1];
    filter_re = c->argv[2];

    filter_value = get_geoip_filter_value(filter_id);
    if (filter_value == NULL) {
      c = find_config_next(c, c->next, CONF_PARAM, "GeoIPAllowFilter", FALSE);
      continue;
    }

    filter_name = get_geoip_filter_name(filter_id);

    res = pr_regexp_exec(filter_re, filter_value, 0, NULL, 0, 0, 0);
    pr_trace_msg(trace_channel, 12,
      "%s filter value %s %s GeoIPAllowFilter pattern '%s'",
      filter_name, filter_value, res == 0 ? "matched" : "did not match",
      filter_pattern);

    if (res == 0) {
      matched_allow_filter = TRUE;
      break;
    }

    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "%s filter value '%s' did not match GeoIPAllowFilter pattern '%s'",
      filter_name, filter_value, filter_pattern);

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPAllowFilter", FALSE);
  }

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPDenyFilter", FALSE);
  while (c) {
    int filter_id, res;
    pr_regex_t *filter_re;
    const char *filter_name, *filter_pattern, *filter_value;

    pr_signals_handle();

    filter_id = *((int *) c->argv[0]);
    filter_pattern = c->argv[1];
    filter_re = c->argv[2];

    filter_value = get_geoip_filter_value(filter_id);
    if (filter_value == NULL) {
      c = find_config_next(c, c->next, CONF_PARAM, "GeoIPDenyFilter", FALSE);
      continue;
    }

    filter_name = get_geoip_filter_name(filter_id);

    res = pr_regexp_exec(filter_re, filter_value, 0, NULL, 0, 0, 0);
    pr_trace_msg(trace_channel, 12,
      "%s filter value %s %s GeoIPDenyFilter pattern '%s'",
      filter_name, filter_value, res == 0 ? "matched" : "did not match",
      filter_pattern);

    if (res == 0) {
      (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
        "%s filter value '%s' matched GeoIPDenyFilter pattern '%s'",
        filter_name, filter_value, filter_pattern);
      return -1;
    }

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPDenyFilter", FALSE);
  }
#endif /* !HAVE_REGEX_H or !HAVE_REGCOMP */

  switch (policy) {
    case GEOIP_POLICY_ALLOW_DENY:
      allow_conn = 0;
      break;

    case GEOIP_POLICY_DENY_ALLOW:
      if (matched_allow_filter == FALSE) {
        /* If we have not explicitly matched any allow filters, then
         * reject the connection.
         */
        allow_conn = -1;
      }
      break;
  }

  return allow_conn;
}
Exemple #10
0
MODRET site_chgrp(cmd_rec *cmd) {
  int res;
  gid_t gid;
  char *path = NULL, *tmp = NULL, *arg = "";
  struct stat st;
  register unsigned int i = 0;
#ifdef PR_USE_REGEX
  pr_regex_t *pre;
#endif

  if (cmd->argc < 3) {
    pr_response_add_err(R_500, _("'SITE %s' not understood"),
      _get_full_cmd(cmd));
    return NULL;
  }

  /* Construct the target file name by concatenating all the parameters after
   * the mode, 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,
        _("SITE %s: Illegal character sequence in command"),
        (char *) cmd->argv[1]);

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

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

#ifdef PR_USE_REGEX
  pre = get_param_ptr(CURRENT_CONF, "PathAllowFilter", FALSE);
  if (pre != NULL &&
      pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) != 0) {
    pr_log_debug(DEBUG2, "'%s %s' denied by PathAllowFilter",
      (char *) cmd->argv[0], arg);
    pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg);

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

  pre = get_param_ptr(CURRENT_CONF, "PathDenyFilter", FALSE);
  if (pre != NULL &&
      pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) == 0) {
    pr_log_debug(DEBUG2, "'%s %s' denied by PathDenyFilter",
      (char *) cmd->argv[0], arg);
    pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg);

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

  if (pr_fsio_lstat(arg, &st) == 0) {
    if (S_ISLNK(st.st_mode)) {
      char link_path[PR_TUNABLE_PATH_MAX];
      int len;

      memset(link_path, '\0', sizeof(link_path));
      len = dir_readlink(cmd->tmp_pool, arg, link_path, sizeof(link_path)-1,
        PR_DIR_READLINK_FL_HANDLE_REL_PATH);
      if (len > 0) {
        link_path[len] = '\0';
        arg = pstrdup(cmd->tmp_pool, link_path);
      }
    }
  }

  path = dir_realpath(cmd->tmp_pool, arg);
  if (path == NULL) {
    int xerrno = errno;

    pr_response_add_err(R_550, "%s: %s", arg, strerror(xerrno));

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

  /* Map the given group argument, if a string, to a GID.  If already a
   * number, pass through as is.
   */
  gid = strtoul(cmd->argv[1], &tmp, 10);

  if (tmp && *tmp) {

    /* Try the parameter as a group name. */
    gid = pr_auth_name2gid(cmd->tmp_pool, cmd->argv[1]);
    if (gid == (gid_t) -1) {
      int xerrno = EINVAL;

      pr_log_debug(DEBUG9,
        "SITE CHGRP: Unable to resolve group name '%s' to GID",
        (char *) cmd->argv[1]);
      pr_response_add_err(R_550, "%s: %s", arg, strerror(xerrno));

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

  res = core_chgrp(cmd, path, (uid_t) -1, gid);
  if (res < 0) {
    int xerrno = errno;

    (void) pr_trace_msg("fileperms", 1, "%s, user '%s' (UID %s, GID %s): "
      "error chown'ing '%s' to GID %s: %s", (char *) cmd->argv[0], session.user,
      pr_uid2str(cmd->tmp_pool, session.uid),
      pr_gid2str(cmd->tmp_pool, session.gid), path,
      pr_gid2str(cmd->tmp_pool, gid), strerror(xerrno));

    pr_response_add_err(R_550, "%s: %s", arg, strerror(xerrno));

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

  pr_response_add(R_200, _("SITE %s command successful"),
    (char *) cmd->argv[0]);
  return PR_HANDLED(cmd);
}
Exemple #11
0
MODRET site_chmod(cmd_rec *cmd) {
  int res;
  mode_t mode = 0;
  char *dir, *endp, *mode_str, *tmp, *arg = "";
  struct stat st;
  register unsigned int i = 0;
#ifdef PR_USE_REGEX
  pr_regex_t *pre;
#endif

  if (cmd->argc < 3) {
    pr_response_add_err(R_500, _("'SITE %s' not understood"),
      _get_full_cmd(cmd));
    return NULL;
  }

  /* Construct the target file name by concatenating all the parameters after
   * the mode, 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,
        _("SITE %s: Illegal character sequence in command"),
        (char *) cmd->argv[1]);

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

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

#ifdef PR_USE_REGEX
  pre = get_param_ptr(CURRENT_CONF, "PathAllowFilter", FALSE);
  if (pre != NULL &&
      pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) != 0) {
    pr_log_debug(DEBUG2, "'%s %s %s' denied by PathAllowFilter",
      (char *) cmd->argv[0], (char *) cmd->argv[1], arg);
    pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg);

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

  pre = get_param_ptr(CURRENT_CONF, "PathDenyFilter", FALSE);
  if (pre != NULL &&
      pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) == 0) {
    pr_log_debug(DEBUG2, "'%s %s %s' denied by PathDenyFilter",
      (char *) cmd->argv[0], (char *) cmd->argv[1], arg);
    pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg);

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

  if (pr_fsio_lstat(arg, &st) == 0) {
    if (S_ISLNK(st.st_mode)) {
      char link_path[PR_TUNABLE_PATH_MAX];
      int len;

      memset(link_path, '\0', sizeof(link_path));
      len = dir_readlink(cmd->tmp_pool, arg, link_path, sizeof(link_path)-1,
        PR_DIR_READLINK_FL_HANDLE_REL_PATH);
      if (len > 0) {
        link_path[len] = '\0';
        arg = pstrdup(cmd->tmp_pool, link_path);
      }
    }
  }

  dir = dir_realpath(cmd->tmp_pool, arg);
  if (dir == NULL) {
    int xerrno = errno;

    pr_response_add_err(R_550, "%s: %s", arg, strerror(xerrno));

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

  /* If the first character isn't '0', prepend it and attempt conversion.
   * This will fail if the chmod is a symbolic, but takes care of the
   * case where an octal number is sent without the leading '0'.
   */
  mode_str = cmd->argv[1];
  if (mode_str[0] != '0') {
    tmp = pstrcat(cmd->tmp_pool, "0", mode_str, NULL);

  } else {
    tmp = mode_str;
  }

  mode = strtol(tmp, &endp, 0);
  if (endp && *endp) {
    /* It's not an absolute number, try symbolic */
    char *cp = mode_str;
    int mask = 0, mode_op = 0, curr_mode = 0, curr_umask = umask(0);
    int invalid = 0;
    char *who, *how, *what;

    umask(curr_umask);
    mode = 0;

    if (pr_fsio_stat(dir, &st) != -1) {
      curr_mode = st.st_mode;
    }

    while (TRUE) {
      pr_signals_handle();

      who = pstrdup(cmd->tmp_pool, cp);

      tmp = strpbrk(who, "+-=");
      if (tmp != NULL) {
        how = pstrdup(cmd->tmp_pool, tmp);
        if (*how != '=') {
          mode = curr_mode;
        }

        *tmp = '\0';

      } else {
        invalid++;
        break;
      }

      tmp = strpbrk(how, "rwxXstugo");
      if (tmp != NULL) {
        what = pstrdup(cmd->tmp_pool, tmp);
        *tmp = '\0';

      } else {
        invalid++;
        break;
      }

      cp = what;
      while (cp) {
        switch (*who) {
          case 'u':
            mask = 0077;
            break;

          case 'g':
            mask = 0707;
            break;

          case 'o':
            mask = 0770;
            break;

          case 'a':
            mask = 0000;
            break;

          case '\0':
            mask = curr_umask;
            break;

          default:
            invalid++;
            break;
        }

        if (invalid)
          break;

        switch (*how) {
          case '+':
          case '-':
          case '=':
            break;

          default:
            invalid++;
        }

        if (invalid)
          break;

        switch (*cp) {
          case 'r':
            mode_op |= (S_IRUSR|S_IRGRP|S_IROTH);
            break;

          case 'w':
            mode_op |= (S_IWUSR|S_IWGRP|S_IWOTH);
            break;

          case 'x':
            mode_op |= (S_IXUSR|S_IXGRP|S_IXOTH);
            break;

          /* 'X' not implemented */
          case 's':
            /* setuid */
            mode_op |= S_ISUID;
            break;

          case 't':
            /* sticky */
            mode_op |= S_ISVTX;
            break;

          case 'o':
            mode_op |= (curr_mode & S_IRWXO);
            mode_op |= ((curr_mode & S_IRWXO) << 3);
            mode_op |= ((curr_mode & S_IRWXO) << 6);
            break;

          case 'g':
            mode_op |= ((curr_mode & S_IRWXG) >> 3);
            mode_op |= (curr_mode & S_IRWXG);
            mode_op |= ((curr_mode & S_IRWXG) << 3);
            break;

          case 'u':
            mode_op |= ((curr_mode & S_IRWXU) >> 6);
            mode_op |= ((curr_mode & S_IRWXU) >> 3);
            mode_op |= (curr_mode & S_IRWXU);
            break;

          case '\0':
            /* Apply the mode and move on */
            switch (*how) {
              case '+':
              case '=':
                mode |= (mode_op & ~mask);
                break;

              case '-':
                mode &= ~(mode_op & ~mask);
                break;
            }

            mode_op = 0;
            if (*who && *(who+1)) {
              who++;
              cp = what;
              continue;

            } else {
              cp = NULL;
            }
            break;

          default:
            invalid++;
        }

        if (invalid) {
          break;
        }

        if (cp) {
          cp++;
        }
      }
      break;
    }

    if (invalid) {
      pr_response_add_err(R_550, _("'%s': invalid mode"), (char *) cmd->argv[1]);

      pr_cmd_set_errno(cmd, EINVAL);
      errno = EINVAL;
      return PR_ERROR(cmd);
    }
  }
Exemple #12
0
static int check_geoip_filters(geoip_policy_e policy) {
  int allow_conn = 0, matched_allow_filter = -1, matched_deny_filter = -1;
#if PR_USE_REGEX
  config_rec *c;

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPAllowFilter", FALSE);
  while (c != NULL) {
    register unsigned int i;
    int matched = TRUE;
    array_header *filters;

    pr_signals_handle();

    if (matched_allow_filter == -1) {
      matched_allow_filter = FALSE;
    }

    filters = c->argv[0];

    for (i = 0; i < filters->nelts; i++) {
      int filter_id, res;
      struct geoip_filter *filter;
      pr_regex_t *filter_re;
      const char *filter_name, *filter_pattern, *filter_value;

      filter = ((struct geoip_filter **) filters->elts)[i]; 
      filter_id = filter->filter_id;
      filter_pattern = filter->filter_pattern;
      filter_re = filter->filter_re;

      filter_value = get_geoip_filter_value(filter_id);
      if (filter_value == NULL) {
        matched = FALSE;
        break;
      }

      filter_name = get_geoip_filter_name(filter_id);

      res = pr_regexp_exec(filter_re, filter_value, 0, NULL, 0, 0, 0);
      pr_trace_msg(trace_channel, 12,
        "%s filter value %s %s GeoIPAllowFilter pattern '%s'",
        filter_name, filter_value, res == 0 ? "matched" : "did not match",
        filter_pattern);
      if (res == 0) {
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "%s filter value '%s' matched GeoIPAllowFilter pattern '%s'",
          filter_name, filter_value, filter_pattern);

      } else {
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "%s filter value '%s' did not match GeoIPAllowFilter pattern '%s'",
          filter_name, filter_value, filter_pattern);
          matched = FALSE;
          break;
      }
    }

    if (matched == TRUE) {
      matched_allow_filter = TRUE;
      break;
    }

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPAllowFilter", FALSE);
  }

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPDenyFilter", FALSE);
  while (c != NULL) {
    register unsigned int i;
    int matched = TRUE;
    array_header *filters;

    pr_signals_handle();

    if (matched_deny_filter == -1) {
      matched_deny_filter = FALSE;
    }

    filters = c->argv[0];

    for (i = 0; i < filters->nelts; i++) {
      int filter_id, res;
      struct geoip_filter *filter;
      pr_regex_t *filter_re;
      const char *filter_name, *filter_pattern, *filter_value;

      filter = ((struct geoip_filter **) filters->elts)[i];
      filter_id = filter->filter_id;
      filter_pattern = filter->filter_pattern;
      filter_re = filter->filter_re;

      filter_value = get_geoip_filter_value(filter_id);
      if (filter_value == NULL) {
        matched = FALSE;
        break;
      }

      filter_name = get_geoip_filter_name(filter_id);

      res = pr_regexp_exec(filter_re, filter_value, 0, NULL, 0, 0, 0);
      pr_trace_msg(trace_channel, 12,
        "%s filter value %s %s GeoIPDenyFilter pattern '%s'",
        filter_name, filter_value, res == 0 ? "matched" : "did not match",
        filter_pattern);
      if (res == 0) {
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "%s filter value '%s' matched GeoIPDenyFilter pattern '%s'",
          filter_name, filter_value, filter_pattern);
      } else {
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "%s filter value '%s' did not match GeoIPDenyFilter pattern '%s'",
          filter_name, filter_value, filter_pattern);
        matched = FALSE;
        break;
      }
    }

    if (matched == TRUE) {
      matched_deny_filter = TRUE;
      break;
    }

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPDenyFilter", FALSE);
  }
#endif /* !HAVE_REGEX_H or !HAVE_REGCOMP */

  switch (policy) {
    case GEOIP_POLICY_ALLOW_DENY:
      if (matched_deny_filter == TRUE &&
          matched_allow_filter != TRUE) {
        /* If we explicitly matched any deny filters AND have NOT explicitly
         * matched any allow filters, the connection is rejected, otherwise,
         * it is allowed.
         */
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "client matched GeoIPDenyFilter, rejecting connection");
        allow_conn = -1;

      } else {
        pr_trace_msg(trace_channel, 9,
          "allowing client connection (policy 'allow,deny')");
      }
      break;

    case GEOIP_POLICY_DENY_ALLOW:
      if (matched_allow_filter == FALSE) {
        /* If we have not explicitly matched any allow filters, then
         * reject the connection.
         */
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "client did not match any GeoIPAllowFilters, rejecting connection");
        allow_conn = -1;

      } else {
        pr_trace_msg(trace_channel, 9,
          "allowing client connection (policy 'deny,allow')");
      }
      break;
  }

  return allow_conn;
}