📄 mod_wrap2.c
字号:
} 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 + -