Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal for passing a structure to ACL checking routines #2

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -437,14 +437,15 @@ tests_server_accept_t_LDFLAGS = $(GSSAPI_LDFLAGS) $(KRB5_LDFLAGS) \
tests_server_accept_t_LDADD = tests/tap/libtap.a util/libutil.la \
portable/libportable.la $(GSSAPI_LIBS) $(KRB5_LIBS) $(GPUT_LIBS) \
$(PCRE_LIBS) $(LIBEVENT_LIBS)
tests_server_acl_t_SOURCES = tests/server/acl-t.c $(SERVER_FILES)
tests_server_acl_t_SOURCES = tests/server/acl-t.c tests/server/acl-helpers.c $(SERVER_FILES)
tests_server_acl_t_LDFLAGS = $(GPUT_LDFLAGS) $(PCRE_LDFLAGS) \
$(LIBEVENT_LDFLAGS)
tests_server_acl_t_LDADD = tests/tap/libtap.a util/libutil.la \
portable/libportable.la $(GPUT_LIBS) $(PCRE_LIBS) $(LIBEVENT_LIBS)
tests_server_acl_localgroup_t_SOURCES = tests/server/acl/localgroup-t.c \
$(SERVER_FILES) tests/server/acl/fake-getgrnam.c \
tests/server/acl/fake-getgrnam.h tests/server/acl/fake-getpwnam.c \
tests/server/acl-helpers.c \
tests/server/acl/fake-getpwnam.h
tests_server_acl_localgroup_t_LDFLAGS = $(GPUT_LDFLAGS) $(PCRE_LDFLAGS) \
$(LIBEVENT_LDFLAGS)
Expand Down
26 changes: 24 additions & 2 deletions server/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ server_send_summary(struct client *client, struct config *config)
int status_all = 0;
struct process process;
struct evbuffer *output = NULL;
struct request *request = NULL;

/* Create a buffer to hold all the output for protocol version one. */
if (client->protocol == 1) {
Expand All @@ -106,6 +107,13 @@ server_send_summary(struct client *client, struct config *config)
die("internal error: cannot create output buffer");
}

/* Fill up request */
request = (struct request *) xmalloc(sizeof(struct request));
request->user = client->user;
request->command = "help";
request->subcommand = NULL;
request->argv = NULL;

/*
* Check each line in the config to find any that are "<command> ALL"
* lines, the user is authorized to run, and which have a summary field
Expand All @@ -117,7 +125,7 @@ server_send_summary(struct client *client, struct config *config)
rule = config->rules[i];
if (strcmp(rule->subcommand, "ALL") != 0)
continue;
if (!server_config_acl_permit(rule, client->user))
if (!server_config_acl_permit(rule, (const struct request *) request))
continue;
if (rule->summary == NULL)
continue;
Expand Down Expand Up @@ -151,6 +159,9 @@ server_send_summary(struct client *client, struct config *config)
free(req_argv);
}

if (request != NULL)
free(request);

/*
* Sets the last process status to 0 if all succeeded, or the last failed
* exit status if any commands gave non-zero. Return that we had output
Expand Down Expand Up @@ -299,6 +310,7 @@ server_run_command(struct client *client, struct config *config,
char *subcommand = NULL;
char *helpsubcommand = NULL;
struct rule *rule = NULL;
struct request *request = NULL;
char **req_argv = NULL;
size_t i;
bool ok = false;
Expand Down Expand Up @@ -400,7 +412,15 @@ server_run_command(struct client *client, struct config *config,
server_send_error(client, ERROR_UNKNOWN_COMMAND, "Unknown command");
goto done;
}
if (!server_config_acl_permit(rule, user)) {

/* Fill up request */
request = (struct request *) xmalloc(sizeof(struct request));
request->user = user;
request->command = xstrdup(command);
request->subcommand = (subcommand == NULL) ? NULL : xstrdup(subcommand);
request->argv = NULL;

if (!server_config_acl_permit(rule, request)) {
notice("access denied: user %s, command %s%s%s", user, command,
(subcommand == NULL) ? "" : " ",
(subcommand == NULL) ? "" : subcommand);
Expand Down Expand Up @@ -448,6 +468,8 @@ server_run_command(struct client *client, struct config *config,
}

done:
if (request != NULL)
free(request);
free(command);
free(subcommand);
free(helpsubcommand);
Expand Down
69 changes: 48 additions & 21 deletions server/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ struct config_option {
/* Holds information about ACL schemes */
struct acl_scheme {
const char *name;
enum config_status (*check)(const char *user, const char *data,
enum config_status (*check)(const struct request *request, const char *data,
const char *file, int lineno);
};

Expand All @@ -91,8 +91,8 @@ struct acl_scheme {
#define ACL_SCHEME_PRINC 1

/* Forward declarations. */
static enum config_status acl_check(const char *user, const char *entry,
int def_index, const char *file,
static enum config_status acl_check(const struct request *request,
const char *entry, int def_index, const char *file,
int lineno);

/*
Expand Down Expand Up @@ -585,7 +585,7 @@ read_conf_file(void *data, const char *name)
static enum config_status
acl_check_file_internal(void *data, const char *aclfile)
{
const char *user = data;
struct request *request = (struct request *) data;
FILE *file = NULL;
char buffer[BUFSIZ];
char *p;
Expand Down Expand Up @@ -624,11 +624,11 @@ acl_check_file_internal(void *data, const char *aclfile)

/* Parse the line. */
if (strchr(p, ' ') == NULL)
s = acl_check(user, p, ACL_SCHEME_PRINC, aclfile, lineno);
s = acl_check(request, p, ACL_SCHEME_PRINC, aclfile, lineno);
else {
line = vector_split_space(buffer, NULL);
if (line->count == 2 && strcmp(line->strings[0], "include") == 0) {
s = acl_check(data, line->strings[1], ACL_SCHEME_FILE,
s = acl_check(request, line->strings[1], ACL_SCHEME_FILE,
aclfile, lineno);
vector_free(line);
line = NULL;
Expand Down Expand Up @@ -672,11 +672,11 @@ acl_check_file_internal(void *data, const char *aclfile)
* remaining result, which should be CONFIG_SUCCESS or CONFIG_NOMATCH.
*/
static enum config_status
acl_check_file(const char *user, const char *aclfile, const char *file,
int lineno)
acl_check_file(const struct request *request, const char *aclfile,
const char *file, int lineno)
{
return handle_include(aclfile, file, lineno, acl_check_file_internal,
(void *) user);
(void *) request);
}


Expand All @@ -689,9 +689,10 @@ acl_check_file(const char *user, const char *aclfile, const char *file,
* aren't.
*/
static enum config_status
acl_check_princ(const char *user, const char *data, const char *file UNUSED,
acl_check_princ(const struct request *request, const char *data, const char *file UNUSED,
int lineno UNUSED)
{
char *user = (char *) request->user;
return (strcmp(user, data) == 0) ? CONFIG_SUCCESS : CONFIG_NOMATCH;
}

Expand Down Expand Up @@ -720,12 +721,12 @@ acl_check_princ(const char *user, const char *data, const char *file UNUSED,
* Any other result indicates a processing error and is returned as-is.
*/
static enum config_status
acl_check_deny(const char *user, const char *data, const char *file,
acl_check_deny(const struct request *request, const char *data, const char *file,
int lineno)
{
enum config_status s;

s = acl_check(user, data, ACL_SCHEME_PRINC, file, lineno);
s = acl_check(request, data, ACL_SCHEME_PRINC, file, lineno);
switch (s) {
case CONFIG_SUCCESS: return CONFIG_DENY;
case CONFIG_NOMATCH: return CONFIG_NOMATCH;
Expand Down Expand Up @@ -768,9 +769,10 @@ server_config_set_gput_file(char *file UNUSED)
*/
#ifdef HAVE_GPUT
static enum config_status
acl_check_gput(const char *user, const char *data, const char *file,
acl_check_gput(const struct request *request, const char *data, const char *file,
int lineno)
{
char *user = request->user;
GPUT *G;
char *role, *xform, *xform_start, *xform_end;
enum config_status s;
Expand Down Expand Up @@ -828,9 +830,10 @@ acl_check_gput(const char *user, const char *data, const char *file,
*/
#ifdef HAVE_PCRE
static enum config_status
acl_check_pcre(const char *user, const char *data, const char *file,
acl_check_pcre(const struct request *request, const char *data, const char *file,
int lineno)
{
char *user = (char *) request->user;
pcre *regex;
const char *error;
int offset, status;
Expand Down Expand Up @@ -865,9 +868,10 @@ acl_check_pcre(const char *user, const char *data, const char *file,
*/
#ifdef HAVE_REGCOMP
static enum config_status
acl_check_regex(const char *user, const char *data, const char *file,
acl_check_regex(const struct request *request, const char *data, const char *file,
int lineno)
{
char *user = (char *) request->user;
regex_t regex;
char error[BUFSIZ];
int status;
Expand Down Expand Up @@ -1031,9 +1035,10 @@ acl_getgrnam(const char *group, struct group **grp, char **buffer)
* file name and line number.
*/
static enum config_status
acl_check_localgroup(const char *user, const char *group,
acl_check_localgroup(const struct request *request, const char *group,
const char *file, int lineno)
{
char *user = (char *) request->user;
struct passwd *pw;
struct group *gr = NULL;
char *grbuffer = NULL;
Expand Down Expand Up @@ -1094,6 +1099,25 @@ acl_check_localgroup(const char *user, const char *group,

#endif /* HAVE_KRB5 && HAVE_GETGRNAM_R */

/*
* The ACL check operation for UNIX local group membership. Takes the user to
* check, the group of which they have to be a member, and the referencing
* file name and line number.
*/
#if 0
static enum config_status
acl_check_exec(const char *user, const char *program,
const char *file, int lineno)
{

enum config_status result;

result = CONFIG_NOMATCH;

done:
return result;
}
#endif

/*
* The table relating ACL scheme names to functions. The first two ACL
Expand All @@ -1104,6 +1128,7 @@ static const struct acl_scheme schemes[] = {
{ "file", acl_check_file },
{ "princ", acl_check_princ },
{ "deny", acl_check_deny },
// { "exec", acl_check_exec },
#ifdef HAVE_GPUT
{ "gput", acl_check_gput },
#else
Expand All @@ -1129,15 +1154,15 @@ static const struct acl_scheme schemes[] = {


/*
* The access control check switch. Takes the user to check, the ACL entry,
* The access control check switch. Takes the request to check, the ACL entry,
* default scheme index, and referencing file name and line number.
*
* Returns CONFIG_SUCCESS if the user is authorized, CONFIG_NOMATCH if they
* aren't, CONFIG_ERROR on some sort of failure (such as failure to read a
* file or a syntax error), and CONFIG_DENY for an explicit deny.
*/
static enum config_status
acl_check(const char *user, const char *entry, int def_index,
acl_check(const struct request *request, const char *entry, int def_index,
const char *file, int lineno)
{
const struct acl_scheme *scheme;
Expand Down Expand Up @@ -1167,7 +1192,7 @@ acl_check(const char *user, const char *entry, int def_index,
scheme->name);
return CONFIG_ERROR;
}
return scheme->check(user, data, file, lineno);
return scheme->check(request, data, file, lineno);
}


Expand Down Expand Up @@ -1219,16 +1244,18 @@ server_config_free(struct config *config)
* otherwise.
*/
bool
server_config_acl_permit(const struct rule *rule, const char *user)
server_config_acl_permit(const struct rule *rule, const struct request *request)
{
char **acls = rule->acls;
size_t i;
enum config_status status;

fprintf(stderr, "request->user = '%s'\n", request->user);

if (strcmp(acls[0], "ANYUSER") == 0)
return true;
for (i = 0; acls[i] != NULL; i++) {
status = acl_check(user, acls[i], ACL_SCHEME_FILE, rule->file,
status = acl_check(request, acls[i], ACL_SCHEME_FILE, rule->file,
rule->lineno);
if (status == 0)
return true;
Expand Down
10 changes: 9 additions & 1 deletion server/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ struct rule {
char **acls; /* Full file names of ACL files. */
};

/* Holds the detail of command, subcommand and args requested by remote user */
struct request {
char *user;
char *command;
char *subcommand;
char **argv;
};

/* Holds the complete parsed configuration for remctld. */
struct config {
struct rule **rules;
Expand Down Expand Up @@ -129,7 +137,7 @@ void server_log_command(struct iovec **, struct rule *, const char *user);
/* Configuration file functions. */
struct config *server_config_load(const char *file);
void server_config_free(struct config *);
bool server_config_acl_permit(const struct rule *, const char *user);
bool server_config_acl_permit(const struct rule *, const struct request *request);
void server_config_set_gput_file(char *file);

/* Running commands. */
Expand Down
25 changes: 25 additions & 0 deletions tests/server/acl-helpers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

#include <tests/server/acl-helpers.h>

static struct request *srequest = NULL;

struct request *new_request(const char *user,
const char *command,
const char *subcommand,
const char **argv)
{

struct request *request = NULL;

if (srequest == NULL)
srequest = (struct request *) malloc(sizeof(struct request));

request = srequest;

request->user = (char *) user;
request->command = (char *) command;
request->subcommand = (char *) subcommand;
request->argv = (char **) argv;

return request;
}
14 changes: 14 additions & 0 deletions tests/server/acl-helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef REMCTL_TESTS_HELPERS_H
#define REMCTL_TESTS_HELPERS_H 1

#include <util/xmalloc.h>
#include <server/internal.h>

struct request *new_request(const char *user,
const char *command,
const char *subcommand,
const char **argv);

#define USER_ONLY_REQUEST(user) new_request(user, NULL, NULL, NULL)

#endif
Loading