⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_wrap2.c

📁 ProFTPd 是一款基于GPL协议的可配置的FTP服务器
💻 C
📖 第 1 页 / 共 3 页
字号:
  } else {    /* user@host */    match = (wrap2_match_host(host, conn->client) &&      wrap2_match_string(tok, wrap2_get_user(conn)));    if (match)      wrap2_log("client matches '%s@%s'", tok, host);  }  return match;}static unsigned char wrap2_match_daemon(char *tok, wrap2_conn_t *conn) {  unsigned char match = FALSE;  char *host = NULL;  host = wrap2_strsplit(tok + 1, '@');  if (host == 0) {    /* Plain daemon */    match = wrap2_match_string(tok, WRAP2_GET_DAEMON(conn));    if (match)      wrap2_log("daemon matches '%s'", tok);  } else {    /* daemon@host */    match = (wrap2_match_string(tok, WRAP2_GET_DAEMON(conn)) &&      wrap2_match_host(host, conn->server));    if (match)      wrap2_log("daemon matches '%s@%s'", tok, host);  }  return match;}static unsigned char wrap2_match_list(array_header *list, wrap2_conn_t *conn,    unsigned char (*match_token)(), unsigned int list_idx) {  register unsigned int i;  char **tokens = NULL;  if (list == NULL)    return FALSE;  tokens = list->elts;  /* Process tokens one at a time. We have exhausted all possible matches   * when we reach an "EXCEPT" token or the end of the list. If we do find   * a match, look for an "EXCEPT" list and recurse to determine whether   * the match is affected by any exceptions.   */  for (i = list_idx; i < list->nelts; i++) {    char *token = wrap2_skip_whitespace(tokens[i]);    if (strcasecmp(token, "EXCEPT") == 0) {      /* EXCEPT -- give up now. */      return FALSE;    }    if (match_token(token, conn)) {      register unsigned int j;      /* If yes, look for exceptions */      for (j = i + 1; j < list->nelts; j++) {              token = wrap2_skip_whitespace(tokens[j]);        if (strcasecmp(token, "EXCEPT") == 0) {          return (wrap2_match_list(list, conn, match_token, j+1) == 0);        }       }      return TRUE;    }  }  return FALSE;}#ifdef WRAP2_USE_OPTIONS#define WRAP2_WHITESPACE		" \t\r\n"/* Options flag for requiring a value. */#define WRAP2_OF_NEED_ARG	(1 << 1)/* Options flag specifying the option must be last in the list. */#define WRAP2_OF_USE_LAST	(1 << 2)/* Options flag allowing for optional values. */#define WRAP2_OF_OPT_ARG	(1 << 3)#define WRAP2_OPT_NEEDS_VAL(o)	\  ((o)->flags & WRAP2_OF_NEED_ARG)#define WRAP2_OPT_ALLOWS_VAL(o)	\  ((o)->flags & (WRAP2_OF_NEED_ARG|WRAP2_OF_OPT_ARG))#define WRAP2_OPT_NEEDS_LAST(o)	\  ((o)->flags & WRAP2_OF_USE_LAST)#define WRAP2_OPT_ALLOW  4#define WRAP2_OPT_DENY   -4/* Options routines */static char *wrap2_opt_trim_string(char *string) {  char *start = NULL, *end = NULL, *cp = NULL;  for (cp = string; *cp; cp++) {    if (!isspace((int) *cp)) {      if (start == '\0')        start = cp;      end = cp;    }  }  return (start ? (end[1] = '\0', start) : cp);}static char *wrap2_opt_get_field(array_header *opts, unsigned int *opt_idx) {  static char *last = "";  char *src = NULL, *dst = NULL, *res = NULL;  char c = 0;  char *string = ((char **) opts->elts)[*opt_idx];  /* This function returns pointers to successive fields within a given   * string. ":" is the field separator; warn if the rule ends in one. It   * replaces a "\:" sequence by ":", without treating the result of   * substitution as field terminator. A null argument means resume search   * where the previous call terminated. This function destroys its   * argument.   *   * Work from explicit source or from memory. While processing \: we   * overwrite the input. This way we do not have to maintain buffers for   * copies of input fields.   */  src = dst = res = (string ? string : last);  if (*src == '\0')    return NULL;  while ((c = *src)) {    if (c == ':') {      if (*++src == '\0')        wrap2_log("option rule ends in ':'");      break;    }    if (c == '\\' && src[1] == ':')      src++;    *dst++ = *src++;  }  last = src;  *dst = '\0';  *opt_idx++;  return res;}/* "allow" option - grant access */static int wrap2_opt_allow(char *val) {  return WRAP2_OPT_ALLOW;}/* "deny" option - deny access */static int wrap2_opt_deny(char *val) {  return WRAP2_OPT_DENY;}/* "nice" option - set process nice value */static int wrap2_opt_nice(char *val) {  int niceness = 10;  char *tmp = NULL;  if (val != 0) {    niceness = (int) strtol(val, &tmp, 10);    if (niceness < 0 || (tmp && *tmp)) {      wrap2_log("bad nice value: '%s'", val);      return 0;    }  }  if (nice(niceness) < 0)    wrap2_log("error handling nice option: %s", strerror(errno));  return 0;}/* "setenv" option - set environment variable */static int wrap2_opt_setenv(char *val) {  char *value = NULL;  if (*(value = val + strcspn(val, WRAP2_WHITESPACE)))    *value++ = '\0';  if (pr_env_set(session.pool, wrap2_opt_trim_string(val),      wrap2_opt_trim_string(value)) < 0) {    wrap2_log("error handling setenv option: %s", strerror(errno));  }  return 0;}struct wrap2_opt {  /* Keyword name (case-insensitive) */  char *name;  /* Options handler */  int (*func)(char *);  /* Modifying flags */  int flags;};static const struct wrap2_opt options_tab[] = {  { "setenv",	wrap2_opt_setenv,	WRAP2_OF_NEED_ARG },  { "nice",	wrap2_opt_nice,		WRAP2_OF_OPT_ARG },  { "allow",	wrap2_opt_allow,	WRAP2_OF_USE_LAST },  { "deny",	wrap2_opt_deny,		WRAP2_OF_USE_LAST },  { NULL, NULL, 0 }};static int wrap2_handle_opts(array_header *options, wrap2_conn_t *conn) {  char *key = NULL, *value = NULL;  char *curr_opt = NULL, *next_opt = NULL;  const struct wrap2_opt *opt = NULL;  unsigned int opt_idx = 0;  for (curr_opt = wrap2_opt_get_field(options, &opt_idx); curr_opt;       curr_opt = next_opt) {    int res = 0;    next_opt = wrap2_opt_get_field(options, &opt_idx);    /* Separate the option into name and value parts. For backwards     * compatibility we ignore exactly one '=' between name and value.     */    curropt = wrap2_opt_trim_string(curr_opt);    if (*(value = curr_opt + strcspn(curr_opt, "=" WRAP2_WHITESPACE))) {      if (*value != '=') {        *value++ = '\0';        value += strspn(value, WRAP2_WHITESPACE);      }      if (*value == '=') {        *value++ = '\0';        value += strspn(value, WRAP2_WHITESPACE);      }    }    if (*value == '\0')      value = NULL;    key = curr_opt;    /* Disallow missing option names (and empty option fields). */    if (*key == '\0') {      wrap2_log("warning: missing option name");      continue;    }    /* Lookup the option-specific info and do some common error checks.     * Delegate option-specific processing to the specific functions.     */    /* Advance to the matching option table entry. */    for (opt = options_tab; opt->name && strcasecmp(opt->name, key) != 0;      opt++);    if (opt->name == 0) {      wrap2_log("unknown option name: '%s'", key);      continue;    }    if (!value && WRAP2_OPT_NEEDS_VAL(opt)) {      wrap2_log("option '%s' requires value", key);      continue;    }    if (value && !WRAP2_OPT_ALLOWS_VAL(opt)) {      wrap2_log("option '%s' requires no value", key);      continue;    }    if (next_opt && WRAP2_OPT_NEEDS_LAST(opt)) {      wrap2_log("option '%s' must be the last option in the list", key);      continue;    }    wrap2_log("processing option: '%s %s'", key, value ? value : "");    res = opt->func(value);    if (res != 0)      return res;  }  return 0;}#endif /* WRAP2_USE_OPTIONS */#define WRAP2_TAB_ALLOW	2#define WRAP2_TAB_MATCH	1#define WRAP2_TAB_DENY	-1static int wrap2_match_table(wrap2_table_t *tab, wrap2_conn_t *conn) {  register unsigned int i;  array_header *daemon_list = NULL, *client_list = NULL, *options_list = NULL;  /* Build daemon list. */  daemon_list = tab->tab_fetch_daemons(tab, wrap2_service_name);  if (daemon_list == NULL ||      daemon_list->nelts == 0) {    wrap2_log("%s", "daemon list is empty");    return 0;  }  wrap2_log("table daemon list:");  for (i = 0; i < daemon_list->nelts; i++) {    char **daemons = daemon_list->elts;    wrap2_log("  %s", daemons[i]);  }  /* Build client list. */  client_list = tab->tab_fetch_clients(tab, wrap2_client_name);  if (client_list == NULL ||      client_list->nelts == 0) {    wrap2_log("%s", "client list is empty");    return 0;  }  wrap2_log("table client list:");  for (i = 0; i < client_list->nelts; i++) {    char **clients = client_list->elts;    wrap2_log("  %s", clients[i]);  }  /* Build options list. */  options_list = tab->tab_fetch_options(tab, wrap2_client_name);  if (options_list &&      options_list->nelts > 0) {    wrap2_log("table options list:");    for (i = 0; i < options_list->nelts; i++) {      char **opts = options_list->elts;      wrap2_log("  %s", opts[i]);    }  }  if (wrap2_match_list(daemon_list, conn, wrap2_match_daemon, 0) &&      wrap2_match_list(client_list, conn, wrap2_match_client, 0)) {#ifdef WRAP2_USE_OPTIONS    int res = 0;    res = wrap2_handle_opts(options_list, conn);    if (res == WRAP2_OPT_ALLOW)      return WRAP2_TAB_ALLOW;    if (res == WRAP2_OPT_DENY)      return WRAP2_TAB_DENY;#endif    return WRAP2_TAB_MATCH;  }  return 0;}static unsigned char wrap2_allow_access(wrap2_conn_t *conn) {  wrap2_table_t *allow_tab = NULL, *deny_tab = NULL;  int res = 0;  /* If the (daemon, client) pair is matched by an entry in the allow   * table, access is granted. Otherwise, if the (daemon, client) pair is   * matched by an entry in the deny table, access is denied. Otherwise,   * access is granted. A non-existent access-control table is treated as an   * empty table.   */  /* Open allow table. */  allow_tab = wrap2_open_table(wrap2_allow_table);  if (allow_tab != NULL) {    /* Check the allow table. */    wrap2_log("%s", "checking allow table rules");    res = wrap2_match_table(allow_tab, conn);    /* Close allow table. */    wrap2_close_table(allow_tab);    destroy_pool(allow_tab->tab_pool);    allow_tab = NULL;    /* No need to check the deny table if the verdict is to explicitly allow. */    if (res == WRAP2_TAB_ALLOW ||        res == WRAP2_TAB_MATCH) {      wrap2_allow_table = wrap2_deny_table = NULL;      return TRUE;    }    if (res == WRAP2_TAB_DENY) {      wrap2_allow_table = wrap2_deny_table = NULL;      return FALSE;    }  } else    wrap2_log("error opening allow table: %s", strerror(errno));  /* Open deny table. */  deny_tab = wrap2_open_table(wrap2_deny_table);  if (deny_tab != NULL) {    /* Check the deny table. */    wrap2_log("%s", "checking deny table rules");    res = wrap2_match_table(deny_tab, conn);    /* Close the deny table. */    wrap2_close_table(deny_tab);    destroy_pool(deny_tab->tab_pool);    deny_tab = NULL;    if (res == WRAP2_TAB_DENY ||        res == WRAP2_TAB_MATCH) {      wrap2_allow_table = wrap2_deny_table = NULL;      return FALSE;     }  } else    wrap2_log("error opening deny table: %s", strerror(errno));  wrap2_allow_table = wrap2_deny_table = NULL;  return TRUE;}/* Boolean OR expression evaluation, returning TRUE if any element in the * expression matches, FALSE otherwise. */static unsigned char wrap2_eval_or_expression(char **acl, array_header *creds) {  unsigned char found = FALSE;  char *elem = NULL, **list = NULL;  if (!acl || !*acl || !creds)    return FALSE;  list = (char **) creds->elts;  for (; *acl; acl++) {    register int i = 0;    elem = *acl;    found = FALSE;    if (*elem == '!') {      found = !found;      elem++;    }    for (i = 0; i < creds->nelts; i++) {      if (strcmp(elem, "*") == 0 || (list[i] && strcmp(elem, list[i]) == 0)) {        found = !found;        break;      }    }    if (found)      return TRUE;  }  return FALSE;}/* Boolean AND expression evaluation, returning TRUE if every element in the * expression matches, FALSE otherwise. */static unsigned char wrap2_eval_and_expression(char **acl, array_header *creds) {  unsigned char found = FALSE;  char *elem = NULL, **list = NULL;  if (!acl || !*acl || !creds)    return FALSE;  list = (char **) creds->elts;  for (; *acl; acl++) {    register int i = 0;    elem = *acl;    found = FALSE;    if (*elem == '!') {      found = !found;      elem++;    }    for (i = 0; i < creds->nelts; i++) {      if (list[i] && strcmp(list[i], elem) == 0) {        found = !found;        break;      }    }    if (!found)       return TRUE;  }  return FALSE;}int wrap2_register(const char *srcname,    wrap2_table_t *(*srcopen)(pool *, char *)) {  /* Note: I know that use of permanent_pool is discouraged as much as   * possible, but in this particular instance, I need a pool that   * persists across rehashes.  The registration of a table type only   * happens once, on module init when the server first starts up, so   * this will not constitute a memory leak.   */  wrap2_regtab_t *regtab = pcalloc(permanent_pool, sizeof(wrap2_regtab_t));  regtab->regtab_name = pstrdup(permanent_pool, srcname);  regtab->regtab_open = srcopen;  /* Add this object to the list. */  regtab->next = wrap2_regtab_list;  wrap2_regtab_list = regtab;  return 0;}/* "builtin" source callbacks. */static int builtin_close_cb(wrap2_table_t *tab) {  return 0;}static array_header *builtin_fetch_clients_cb(wrap2_table_t *tab,    const char *name) {  array_header *list = make_array(tab->tab_pool, 1, sizeof(char *));  *((char **) push_array(list)) = pstrdup(tab->tab_pool, "ALL");  return list;}static array_header *builtin_fetch_daemons_cb(wrap2_table_t *tab,    const char *name) {  array_header *list = make_array(tab->tab_pool, 1, sizeof(char *));  *((char **) push_array(list)) = pstrdup(tab->tab_pool, name);  return list;}static array_header *builtin_fetch_options_cb(wrap2_table_t *tab,    const char *name) {  return NULL;}static wrap2_table_t *builtin_open_cb(pool *parent_pool, char *srcinfo) {  wrap2_table_t *tab = NULL;  pool *tab_pool = make_sub_pool(parent_pool);  /* Do not allow any parameters other than 'all. */  if (strcasecmp(srcinfo, "all") != 0) {    wrap2_log("error: unknown builtin parameter: '%s'", srcinfo);    destroy_pool(tab_pool);    errno = EINVAL;    return NULL;  }  tab = (wrap2_table_t *) pcalloc(tab_pool, sizeof(wrap2_table_t));  tab->tab_pool = tab_pool;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -