END_TEST START_TEST (regexp_cleanup_test) { pr_regex_t *pre, *pre2, *pre3; int res; char *pattern; pattern = "^foo"; pre = pr_regexp_alloc(NULL); res = pr_regexp_compile(pre, pattern, 0); fail_unless(res == 0, "Failed to compile regexp pattern '%s'", pattern); pattern = "bar$"; pre2 = pr_regexp_alloc(NULL); res = pr_regexp_compile(pre2, pattern, 0); fail_unless(res == 0, "Failed to compile regexp pattern '%s'", pattern); pattern = "&baz$"; pre3 = pr_regexp_alloc(NULL); res = pr_regexp_compile_posix(pre3, pattern, 0); fail_unless(res == 0, "Failed to compile POSIX regexp pattern '%s'", pattern); mark_point(); pr_event_generate("core.restart", NULL); mark_point(); pr_event_generate("core.exit", NULL); mark_point(); pr_regexp_free(NULL, pre); mark_point(); pr_regexp_free(NULL, pre2); }
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); }
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); }
END_TEST START_TEST (regexp_get_pattern_test) { pr_regex_t *pre = NULL; int res; const char *str; char *pattern; str = pr_regexp_get_pattern(NULL); fail_unless(str == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); pre = pr_regexp_alloc(NULL); str = pr_regexp_get_pattern(pre); fail_unless(str == NULL, "Failed to handle null pattern"); fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT, strerror(errno), errno); pattern = "^foo"; res = pr_regexp_compile(pre, pattern, 0); fail_unless(res == 0, "Failed to compile regex pattern '%s'", pattern); str = pr_regexp_get_pattern(pre); fail_unless(str != NULL, "Failed to get regex pattern: %s", strerror(errno)); fail_unless(strcmp(str, pattern) == 0, "Expected '%s', got '%s'", pattern, str); pr_regexp_free(NULL, pre); }
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 */ }
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); }
END_TEST START_TEST (regexp_compile_test) { pr_regex_t *pre = NULL; int res; char errstr[256], *pattern; size_t errstrlen; res = pr_regexp_compile(NULL, NULL, 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); res = pr_regexp_compile(pre, NULL, 0); fail_unless(res < 0, "Failed to handle null pattern"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); pattern = "[=foo"; res = pr_regexp_compile(pre, pattern, 0); fail_unless(res != 0, "Successfully compiled pattern unexpectedly"); errstrlen = pr_regexp_error(1, NULL, NULL, 0); fail_unless(errstrlen == 0, "Failed to handle null arguments"); errstrlen = pr_regexp_error(1, pre, NULL, 0); fail_unless(errstrlen == 0, "Failed to handle null buffer"); errstrlen = pr_regexp_error(1, pre, errstr, 0); fail_unless(errstrlen == 0, "Failed to handle zero buffer length"); errstrlen = pr_regexp_error(res, pre, errstr, sizeof(errstr)); fail_unless(errstrlen > 0, "Failed to get regex compilation error string"); pattern = "foo"; res = pr_regexp_compile(pre, pattern, 0); fail_unless(res == 0, "Failed to compile regex pattern '%s'", pattern); pattern = "foo"; res = pr_regexp_compile(pre, pattern, REG_ICASE); fail_unless(res == 0, "Failed to compile regex pattern '%s'", pattern); pr_regexp_free(NULL, pre); }
static int get_filter(pool *p, const char *pattern, pr_regex_t **pre) { int res; *pre = pr_regexp_alloc(&geoip_module); res = pr_regexp_compile(*pre, pattern, 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(&geoip_module, *pre); *pre = NULL; pr_log_pri(PR_LOG_DEBUG, MOD_GEOIP_VERSION ": pattern '%s' failed regex compilation: %s", pattern, errstr); errno = EINVAL; return -1; } return res; }
MODRET add_lmd_allow_user_regex(cmd_rec *cmd) { array_header *list; pr_regex_t *pre; int i, res; config_rec *c; if(cmd->argc < 2) CONF_ERROR(cmd, "missing argument"); CHECK_CONF(cmd, CONF_ROOT|CONF_GLOBAL); /* argv => LMDBAllowUserRegex ^test */ c = find_config(cmd->server->conf, CONF_PARAM, "LMDBAllowedUserRegex", FALSE); if(c && c->argv[0]) { list = c->argv[0]; } else { c = add_config_param(cmd->argv[0], 0, NULL); c->argv[0] = list = make_array(cmd->server->pool, 0, sizeof(regex_t *)); } for(i=1; i < cmd->argc; i++) { pre = pr_regexp_alloc(&libmemcached_deny_blacklist_module); res = pr_regexp_compile(pre, cmd->argv[i], 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, "'", cmd->argv[i], "' failed " "regex compilation: ", errstr, NULL)); } *((pr_regex_t **) push_array(list)) = pre; pr_log_debug(DEBUG2, "%s: add LMDBAllowedUserRegex[%d] %s", MODULE_NAME, i, cmd->argv[i]); } return PR_HANDLED(cmd); }
/* 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; }
/* usage: AuthGroupFile path [id <min-max>] [name <regex>] */ MODRET set_authgroupfile(cmd_rec *cmd) { config_rec *c = NULL; authfile_file_t *file = NULL; #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)); 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 (strcmp(cmd->argv[i], "id") == 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 (strcmp(cmd->argv[i], "name") == 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: 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); } }