diff --git libsemanage-2.5/ChangeLog libsemanage-2.5/ChangeLog index 9b4d5b7..469c4b0 100644 --- libsemanage-2.5/ChangeLog +++ libsemanage-2.5/ChangeLog @@ -1,3 +1,20 @@ + * Fixes bug preventing the installation of base modules, from James Carter. +2.6-rc1 2016-09-30 + * make distclean target work, from Nicolas Iooss. + * Do not always print a module name warning, from Miroslav Grepl. + * Use pp module name instead of filename when installing module, from Petr Lautrbach. + * tests: Do not force using gcc, from Nicolas Iooss. + * genhomedircon: remove hardcoded refpolicy strings, from Gary Tierney. + * genhomedircon: add support for %group syntax, from Gary Tierney. + * genhomedircon: generate contexts for logins mapped to the default user, from Gary Tierney. + * Validate and compile file contexts before installing, from Stephen Smalley. + * Swap tcp and udp protocol numbers, from Miroslav Vadkerti. + * Sort object files for deterministic linking order, from Laurent Bigonville. + * Support overriding Makefile RANLIB, from Julien Pivotto. + * Respect CC and PKG_CONFIG environment variable, from Julien Pivotto. + * Fix multiple spelling errors, from Laurent Bigonville. + * genhomedircon: %{USERID} and %{USERNAME} support and code cleanups, from Jason Zaman. + 2.5 2016-02-23 * Do not overwrite CFLAGS in test Makefile, from Nicolas Iooss. * Fix uninitialized variable in direct_commit and direct_api, from Nicolas Iooss. diff --git libsemanage-2.5/include/semanage/handle.h libsemanage-2.5/include/semanage/handle.h index 6cad529..c816590 100644 --- libsemanage-2.5/include/semanage/handle.h +++ libsemanage-2.5/include/semanage/handle.h @@ -130,7 +130,7 @@ int semanage_commit(semanage_handle_t *); #define SEMANAGE_CAN_READ 1 #define SEMANAGE_CAN_WRITE 2 /* returns SEMANAGE_CAN_READ or SEMANAGE_CAN_WRITE if the store is readable - * or writable, respectively. <0 if an error occured */ + * or writable, respectively. <0 if an error occurred */ int semanage_access_check(semanage_handle_t * sh); /* returns 0 if not connected, 1 if connected */ diff --git libsemanage-2.5/src/Makefile libsemanage-2.5/src/Makefile index d1fcc0b..68aab72 100644 --- libsemanage-2.5/src/Makefile +++ libsemanage-2.5/src/Makefile @@ -5,6 +5,7 @@ PYTHON ?= python PYPREFIX ?= $(notdir $(PYTHON)) RUBY ?= ruby RUBYPREFIX ?= $(notdir $(RUBY)) +PKG_CONFIG ?= pkg-config # Installation directories. PREFIX ?= $(DESTDIR)/usr @@ -12,11 +13,11 @@ LIBDIR ?= $(PREFIX)/lib SHLIBDIR ?= $(DESTDIR)/lib INCLUDEDIR ?= $(PREFIX)/include PYLIBVER ?= $(shell $(PYTHON) -c 'import sys;print("python%d.%d" % sys.version_info[0:2])') -PYINC ?= $(shell pkg-config --cflags $(PYPREFIX)) +PYINC ?= $(shell $(PKG_CONFIG) --cflags $(PYPREFIX)) PYLIBDIR ?= $(LIBDIR)/$(PYLIBVER) RUBYLIBVER ?= $(shell $(RUBY) -e 'print RUBY_VERSION.split(".")[0..1].join(".")') RUBYPLATFORM ?= $(shell $(RUBY) -e 'print RUBY_PLATFORM') -RUBYINC ?= $(shell pkg-config --cflags ruby-$(RUBYLIBVER)) +RUBYINC ?= $(shell $(PKG_CONFIG) --cflags ruby-$(RUBYLIBVER)) RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM) LIBBASE=$(shell basename $(LIBDIR)) @@ -50,8 +51,8 @@ SWIGFILES=$(SWIGSO) semanage.py SWIGRUBYSO=$(RUBYPREFIX)_semanage.so LIBSO=$(TARGET).$(LIBVERSION) -GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) semanageswig_python_exception.i -SRCS= $(filter-out $(GENERATED),$(wildcard *.c)) +GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) semanageswig_python_exception.i $(wildcard conf-*.[ch]) +SRCS= $(filter-out $(GENERATED),$(sort $(wildcard *.c))) OBJS= $(patsubst %.c,%.o,$(SRCS)) conf-scan.o conf-parse.o LOBJS= $(patsubst %.c,%.lo,$(SRCS)) conf-scan.lo conf-parse.lo @@ -61,14 +62,12 @@ SWIG_CFLAGS += -Wno-error -Wno-unused-but-set-variable -Wno-unused-variable -Wno -Wno-unused-parameter override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE -RANLIB=ranlib +RANLIB ?= ranlib SWIG = swig -Wall -python -o $(SWIGCOUT) -outdir ./ SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./ -GENERATED=$(SWIGCOUT) $(SWIGRUBYCOUT) $(wildcard conf-*.[ch]) - all: $(LIBA) $(LIBSO) $(LIBPC) pywrap: all $(SWIGSO) @@ -162,7 +161,7 @@ clean: -rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(SWIGLOBJ) $(SWIGSO) $(TARGET) conf-parse.c conf-parse.h conf-scan.c *.o *.lo *~ distclean: clean - rm -f $(SWIGCOUT) $(SWIGFILES) + rm -f $(GENERATED) $(SWIGFILES) indent: ../../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch])) diff --git libsemanage-2.5/src/database.h libsemanage-2.5/src/database.h index e460379..6a4a164 100644 --- libsemanage-2.5/src/database.h +++ libsemanage-2.5/src/database.h @@ -148,7 +148,7 @@ typedef struct dbase_table { * This function must be invoked before using * any of the database functions above. It may be invoked * multiple times, and will update the cache if a commit - * occured between invocations */ + * occurred between invocations */ int (*cache) (struct semanage_handle * handle, dbase_t * dbase); /* Forgets all changes that haven't been written diff --git libsemanage-2.5/src/direct_api.c libsemanage-2.5/src/direct_api.c index 2187b65..e5c72cd 100644 --- libsemanage-2.5/src/direct_api.c +++ libsemanage-2.5/src/direct_api.c @@ -363,6 +363,35 @@ static int semanage_direct_begintrans(semanage_handle_t * sh) /********************* utility functions *********************/ +/* Takes a module stored in 'module_data' and parses its headers. + * Sets reference variables 'module_name' to module's name, and + * 'version' to module's version. The caller is responsible for + * free()ing 'module_name', and 'version'; they will be + * set to NULL upon entering this function. Returns 0 on success, -1 + * if out of memory. + */ +static int parse_module_headers(semanage_handle_t * sh, char *module_data, + size_t data_len, char **module_name, + char **version) +{ + struct sepol_policy_file *pf; + int file_type; + *module_name = *version = NULL; + + if (sepol_policy_file_create(&pf)) { + ERR(sh, "Out of memory!"); + return -1; + } + sepol_policy_file_set_mem(pf, module_data, data_len); + sepol_policy_file_set_handle(pf, sh->sepolh); + if (module_data != NULL && data_len > 0) + sepol_module_package_info(pf, &file_type, module_name, + version); + sepol_policy_file_free(pf); + + return 0; +} + #include #include #include @@ -1524,7 +1553,9 @@ static int semanage_direct_install_file(semanage_handle_t * sh, char *path = NULL; char *filename; char *lang_ext = NULL; + char *module_name = NULL; char *separator; + char *version = NULL; if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) { ERR(sh, "Unable to read file %s\n", install_filename); @@ -1564,10 +1595,29 @@ static int semanage_direct_install_file(semanage_handle_t * sh, lang_ext = separator + 1; } - retval = semanage_direct_install(sh, data, data_len, filename, lang_ext); + if (strcmp(lang_ext, "pp") == 0) { + retval = parse_module_headers(sh, data, data_len, &module_name, &version); + free(version); + if (retval != 0) + goto cleanup; + } + + if (module_name == NULL) { + module_name = strdup(filename); + if (module_name == NULL) { + ERR(sh, "No memory available for module_name.\n"); + retval = -1; + goto cleanup; + } + } else if (strcmp(module_name, filename) != 0) { + fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename); + } + + retval = semanage_direct_install(sh, data, data_len, module_name, lang_ext); cleanup: if (data_len > 0) munmap(data, data_len); + free(module_name); free(path); return retval; diff --git libsemanage-2.5/src/exception.sh libsemanage-2.5/src/exception.sh index 94619d2..d18959c 100644 --- libsemanage-2.5/src/exception.sh +++ libsemanage-2.5/src/exception.sh @@ -9,6 +9,6 @@ echo " } " } -gcc -x c -c -I../include - -aux-info temp.aux < ../include/semanage/semanage.h +${CC:-gcc} -x c -c -I../include - -aux-info temp.aux < ../include/semanage/semanage.h for i in `awk '/extern int/ { print $6 }' temp.aux`; do except $i ; done rm -f -- temp.aux -.o diff --git libsemanage-2.5/src/genhomedircon.c libsemanage-2.5/src/genhomedircon.c index 1a9e87e..cce3884 100644 --- libsemanage-2.5/src/genhomedircon.c +++ libsemanage-2.5/src/genhomedircon.c @@ -48,6 +48,8 @@ #include #include #include +#include +#include /* paths used in get_home_dirs() */ #define PATH_ETC_USERADD "/etc/default/useradd" @@ -73,37 +75,45 @@ which are searched for and replaced */ #define TEMPLATE_HOME_ROOT "HOME_ROOT" #define TEMPLATE_HOME_DIR "HOME_DIR" +/* these are legacy */ #define TEMPLATE_USER "USER" #define TEMPLATE_ROLE "ROLE" +/* new names */ +#define TEMPLATE_USERNAME "%{USERNAME}" +#define TEMPLATE_USERID "%{USERID}" + #define TEMPLATE_SEUSER "system_u" #define TEMPLATE_LEVEL "s0" -#define FALLBACK_USER "user_u" -#define FALLBACK_USER_PREFIX "user" -#define FALLBACK_USER_LEVEL "s0" +#define FALLBACK_SENAME "user_u" +#define FALLBACK_PREFIX "user" +#define FALLBACK_LEVEL "s0" +#define FALLBACK_NAME "[^/]+" +#define FALLBACK_UIDGID "[0-9]+" #define DEFAULT_LOGIN "__default__" -typedef struct { - const char *fcfilepath; - int usepasswd; - const char *homedir_template_path; - char *fallback_user; - char *fallback_user_prefix; - char *fallback_user_level; - semanage_handle_t *h_semanage; - sepol_policydb_t *policydb; -} genhomedircon_settings_t; - typedef struct user_entry { char *name; + char *uid; + char *gid; char *sename; char *prefix; char *home; char *level; + char *login; struct user_entry *next; } genhomedircon_user_entry_t; typedef struct { + const char *fcfilepath; + int usepasswd; + const char *homedir_template_path; + genhomedircon_user_entry_t *fallback; + semanage_handle_t *h_semanage; + sepol_policydb_t *policydb; +} genhomedircon_settings_t; + +typedef struct { const char *search_for; const char *replace_with; } replacement_pair_t; @@ -461,11 +471,29 @@ static int HOME_DIR_PRED(const char *string) return semanage_is_prefix(string, TEMPLATE_HOME_DIR); } +/* new names */ +static int USERNAME_CONTEXT_PRED(const char *string) +{ + return (int)( + (strstr(string, TEMPLATE_USERNAME) != NULL) || + (strstr(string, TEMPLATE_USERID) != NULL) + ); +} + +/* This will never match USER if USERNAME or USERID are found. */ static int USER_CONTEXT_PRED(const char *string) { + if (USERNAME_CONTEXT_PRED(string)) + return 0; + return (int)(strstr(string, TEMPLATE_USER) != NULL); } +static int STR_COMPARATOR(const void *a, const void *b) +{ + return strcmp((const char *) a, (const char *) b); +} + /* make_tempate * @param s the settings holding the paths to various files * @param pred function pointer to function to use as filter for slurp @@ -548,23 +576,12 @@ static int check_line(genhomedircon_settings_t * s, Ustr *line) return result; } -static int write_home_dir_context(genhomedircon_settings_t * s, FILE * out, - semanage_list_t * tpl, const char *user, - const char *seuser, const char *home, - const char *role_prefix, const char *level) +static int write_replacements(genhomedircon_settings_t * s, FILE * out, + const semanage_list_t * tpl, + const replacement_pair_t *repl) { - replacement_pair_t repl[] = { - {.search_for = TEMPLATE_SEUSER,.replace_with = seuser}, - {.search_for = TEMPLATE_HOME_DIR,.replace_with = home}, - {.search_for = TEMPLATE_ROLE,.replace_with = role_prefix}, - {.search_for = TEMPLATE_LEVEL,.replace_with = level}, - {NULL, NULL} - }; Ustr *line = USTR_NULL; - if (fprintf(out, COMMENT_USER_HOME_CONTEXT, user) < 0) - return STATUS_ERR; - for (; tpl; tpl = tpl->next) { line = replace_all(tpl->data, repl); if (!line) @@ -582,6 +599,28 @@ static int write_home_dir_context(genhomedircon_settings_t * s, FILE * out, return STATUS_ERR; } +static int write_home_dir_context(genhomedircon_settings_t * s, FILE * out, + semanage_list_t * tpl, const genhomedircon_user_entry_t *user) +{ + replacement_pair_t repl[] = { + {.search_for = TEMPLATE_SEUSER,.replace_with = user->sename}, + {.search_for = TEMPLATE_HOME_DIR,.replace_with = user->home}, + {.search_for = TEMPLATE_ROLE,.replace_with = user->prefix}, + {.search_for = TEMPLATE_LEVEL,.replace_with = user->level}, + {NULL, NULL} + }; + + if (strcmp(user->name, FALLBACK_NAME) == 0) { + if (fprintf(out, COMMENT_USER_HOME_CONTEXT, FALLBACK_SENAME) < 0) + return STATUS_ERR; + } else { + if (fprintf(out, COMMENT_USER_HOME_CONTEXT, user->name) < 0) + return STATUS_ERR; + } + + return write_replacements(s, out, tpl, repl); +} + static int write_home_root_context(genhomedircon_settings_t * s, FILE * out, semanage_list_t * tpl, char *homedir) { @@ -589,52 +628,54 @@ static int write_home_root_context(genhomedircon_settings_t * s, FILE * out, {.search_for = TEMPLATE_HOME_ROOT,.replace_with = homedir}, {NULL, NULL} }; - Ustr *line = USTR_NULL; - for (; tpl; tpl = tpl->next) { - line = replace_all(tpl->data, repl); - if (!line) - goto fail; - if (check_line(s, line) == STATUS_SUCCESS) { - if (!ustr_io_putfileline(&line, out)) - goto fail; - } - ustr_sc_free(&line); - } - return STATUS_SUCCESS; + return write_replacements(s, out, tpl, repl); +} - fail: - ustr_sc_free(&line); - return STATUS_ERR; +static int write_username_context(genhomedircon_settings_t * s, FILE * out, + semanage_list_t * tpl, + const genhomedircon_user_entry_t *user) +{ + replacement_pair_t repl[] = { + {.search_for = TEMPLATE_USERNAME,.replace_with = user->name}, + {.search_for = TEMPLATE_USERID,.replace_with = user->uid}, + {.search_for = TEMPLATE_ROLE,.replace_with = user->prefix}, + {.search_for = TEMPLATE_SEUSER,.replace_with = user->sename}, + {NULL, NULL} + }; + + return write_replacements(s, out, tpl, repl); } static int write_user_context(genhomedircon_settings_t * s, FILE * out, - semanage_list_t * tpl, const char *user, - const char *seuser, const char *role_prefix) + semanage_list_t * tpl, const genhomedircon_user_entry_t *user) { replacement_pair_t repl[] = { - {.search_for = TEMPLATE_USER,.replace_with = user}, - {.search_for = TEMPLATE_ROLE,.replace_with = role_prefix}, - {.search_for = TEMPLATE_SEUSER,.replace_with = seuser}, + {.search_for = TEMPLATE_USER,.replace_with = user->name}, + {.search_for = TEMPLATE_ROLE,.replace_with = user->prefix}, + {.search_for = TEMPLATE_SEUSER,.replace_with = user->sename}, {NULL, NULL} }; - Ustr *line = USTR_NULL; - for (; tpl; tpl = tpl->next) { - line = replace_all(tpl->data, repl); - if (!line) - goto fail; - if (check_line(s, line) == STATUS_SUCCESS) { - if (!ustr_io_putfileline(&line, out)) - goto fail; - } - ustr_sc_free(&line); + return write_replacements(s, out, tpl, repl); +} + +static int seuser_sort_func(const void *arg1, const void *arg2) +{ + const semanage_seuser_t **u1 = (const semanage_seuser_t **) arg1; + const semanage_seuser_t **u2 = (const semanage_seuser_t **) arg2;; + const char *name1 = semanage_seuser_get_name(*u1); + const char *name2 = semanage_seuser_get_name(*u2); + + if (name1[0] == '%' && name2[0] == '%') { + return 0; + } else if (name1[0] == '%') { + return 1; + } else if (name2[0] == '%') { + return -1; } - return STATUS_SUCCESS; - fail: - ustr_sc_free(&line); - return STATUS_ERR; + return strcmp(name1, name2); } static int user_sort_func(semanage_user_t ** arg1, semanage_user_t ** arg2) @@ -649,15 +690,19 @@ static int name_user_cmp(char *key, semanage_user_t ** val) } static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n, - const char *sen, const char *pre, const char *h, - const char *l) + const char *u, const char *g, const char *sen, + const char *pre, const char *h, const char *l, + const char *ln) { genhomedircon_user_entry_t *temp = NULL; char *name = NULL; + char *uid = NULL; + char *gid = NULL; char *sename = NULL; char *prefix = NULL; char *home = NULL; char *level = NULL; + char *lname = NULL; temp = malloc(sizeof(genhomedircon_user_entry_t)); if (!temp) @@ -665,6 +710,12 @@ static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n, name = strdup(n); if (!name) goto cleanup; + uid = strdup(u); + if (!uid) + goto cleanup; + gid = strdup(g); + if (!gid) + goto cleanup; sename = strdup(sen); if (!sename) goto cleanup; @@ -677,12 +728,18 @@ static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n, level = strdup(l); if (!level) goto cleanup; + lname = strdup(ln); + if (!lname) + goto cleanup; temp->name = name; + temp->uid = uid; + temp->gid = gid; temp->sename = sename; temp->prefix = prefix; temp->home = home; temp->level = level; + temp->login = lname; temp->next = (*list); (*list) = temp; @@ -690,10 +747,13 @@ static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n, cleanup: free(name); + free(uid); + free(gid); free(sename); free(prefix); free(home); free(level); + free(lname); free(temp); return STATUS_ERR; } @@ -708,39 +768,16 @@ static void pop_user_entry(genhomedircon_user_entry_t ** list) temp = *list; *list = temp->next; free(temp->name); + free(temp->uid); + free(temp->gid); free(temp->sename); free(temp->prefix); free(temp->home); free(temp->level); + free(temp->login); free(temp); } -static int set_fallback_user(genhomedircon_settings_t *s, const char *user, - const char *prefix, const char *level) -{ - char *fallback_user = strdup(user); - char *fallback_user_prefix = strdup(prefix); - char *fallback_user_level = NULL; - if (level) - fallback_user_level = strdup(level); - - if (fallback_user == NULL || fallback_user_prefix == NULL || - (fallback_user_level == NULL && level != NULL)) { - free(fallback_user); - free(fallback_user_prefix); - free(fallback_user_level); - return STATUS_ERR; - } - - free(s->fallback_user); - free(s->fallback_user_prefix); - free(s->fallback_user_level); - s->fallback_user = fallback_user; - s->fallback_user_prefix = fallback_user_prefix; - s->fallback_user_level = fallback_user_level; - return STATUS_SUCCESS; -} - static int setup_fallback_user(genhomedircon_settings_t * s) { semanage_seuser_t **seuser_list = NULL; @@ -775,17 +812,20 @@ static int setup_fallback_user(genhomedircon_settings_t * s) if (semanage_user_query(s->h_semanage, key, &u) < 0) { prefix = name; - level = FALLBACK_USER_LEVEL; + level = FALLBACK_LEVEL; } else { prefix = semanage_user_get_prefix(u); level = semanage_user_get_mlslevel(u); if (!level) - level = FALLBACK_USER_LEVEL; + level = FALLBACK_LEVEL; } - if (set_fallback_user(s, seuname, prefix, level) != 0) + if (push_user_entry(&(s->fallback), FALLBACK_NAME, + FALLBACK_UIDGID, FALLBACK_UIDGID, + seuname, prefix, "", level, + FALLBACK_NAME) != 0) errors = STATUS_ERR; semanage_user_key_free(key); if (u) @@ -801,6 +841,202 @@ static int setup_fallback_user(genhomedircon_settings_t * s) return errors; } +static genhomedircon_user_entry_t *find_user(genhomedircon_user_entry_t *head, + const char *name) +{ + for(; head; head = head->next) { + if (strcmp(head->name, name) == 0) { + return head; + } + } + + return NULL; +} + +static int add_user(genhomedircon_settings_t * s, + genhomedircon_user_entry_t **head, + semanage_user_t *user, + const char *name, + const char *sename, + const char *selogin) +{ + if (selogin[0] == '%') { + genhomedircon_user_entry_t *orig = find_user(*head, name); + if (orig != NULL && orig->login[0] == '%') { + ERR(s->h_semanage, "User %s is already mapped to" + " group %s, but also belongs to group %s. Add an" + " explicit mapping for this user to" + " override group mappings.", + name, orig->login + 1, selogin + 1); + return STATUS_ERR; + } else if (orig != NULL) { + // user mappings take precedence + return STATUS_SUCCESS; + } + } + + int retval = STATUS_ERR; + + char *rbuf = NULL; + long rbuflen; + struct passwd pwstorage, *pwent = NULL; + const char *prefix = NULL; + const char *level = NULL; + char uid[11]; + char gid[11]; + + /* Allocate space for the getpwnam_r buffer */ + rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (rbuflen <= 0) + goto cleanup; + rbuf = malloc(rbuflen); + if (rbuf == NULL) + goto cleanup; + + if (user) { + prefix = semanage_user_get_prefix(user); + level = semanage_user_get_mlslevel(user); + + if (!level) { + level = FALLBACK_LEVEL; + } + } else { + prefix = name; + level = FALLBACK_LEVEL; + } + + retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); + if (retval != 0 || pwent == NULL) { + if (retval != 0 && retval != ENOENT) { + goto cleanup; + } + + WARN(s->h_semanage, + "user %s not in password file", name); + retval = STATUS_SUCCESS; + goto cleanup; + } + + int len = strlen(pwent->pw_dir) -1; + for(; len > 0 && pwent->pw_dir[len] == '/'; len--) { + pwent->pw_dir[len] = '\0'; + } + + if (strcmp(pwent->pw_dir, "/") == 0) { + /* don't relabel / genhomdircon checked to see if root + * was the user and if so, set his home directory to + * /root */ + retval = STATUS_SUCCESS; + goto cleanup; + } + + if (ignore(pwent->pw_dir)) { + retval = STATUS_SUCCESS; + goto cleanup; + } + + len = snprintf(uid, sizeof(uid), "%u", pwent->pw_uid); + if (len < 0 || len >= (int)sizeof(uid)) { + goto cleanup; + } + + len = snprintf(gid, sizeof(gid), "%u", pwent->pw_gid); + if (len < 0 || len >= (int)sizeof(gid)) { + goto cleanup; + } + + retval = push_user_entry(head, name, uid, gid, sename, prefix, + pwent->pw_dir, level, selogin); +cleanup: + free(rbuf); + return retval; +} + +static int get_group_users(genhomedircon_settings_t * s, + genhomedircon_user_entry_t **head, + semanage_user_t *user, + const char *sename, + const char *selogin) +{ + int retval = STATUS_ERR; + unsigned int i; + + long grbuflen; + char *grbuf = NULL; + struct group grstorage, *group = NULL; + + long prbuflen; + char *pwbuf = NULL; + struct passwd pwstorage, *pw = NULL; + + grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); + if (grbuflen <= 0) + goto cleanup; + grbuf = malloc(grbuflen); + if (grbuf == NULL) + goto cleanup; + + const char *grname = selogin + 1; + + if (getgrnam_r(grname, &grstorage, grbuf, + (size_t) grbuflen, &group) != 0) { + goto cleanup; + } + + if (group == NULL) { + ERR(s->h_semanage, "Can't find group named %s\n", grname); + goto cleanup; + } + + size_t nmembers = 0; + char **members = group->gr_mem; + + while (*members != NULL) { + nmembers++; + members++; + } + + for (i = 0; i < nmembers; i++) { + const char *uname = group->gr_mem[i]; + + if (add_user(s, head, user, uname, sename, selogin) < 0) { + goto cleanup; + } + } + + prbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (prbuflen <= 0) + goto cleanup; + pwbuf = malloc(prbuflen); + if (pwbuf == NULL) + goto cleanup; + + setpwent(); + while ((retval = getpwent_r(&pwstorage, pwbuf, prbuflen, &pw)) == 0) { + // skip users who also have this group as their + // primary group + if (lfind(pw->pw_name, group->gr_mem, &nmembers, + sizeof(char *), &STR_COMPARATOR)) { + continue; + } + + if (group->gr_gid == pw->pw_gid) { + if (add_user(s, head, user, pw->pw_name, + sename, selogin) < 0) { + goto cleanup; + } + } + } + + retval = STATUS_SUCCESS; +cleanup: + endpwent(); + free(pwbuf); + free(grbuf); + + return retval; +} + static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s, int *errors) { @@ -812,12 +1048,7 @@ static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s, semanage_user_t **u = NULL; const char *name = NULL; const char *seuname = NULL; - const char *prefix = NULL; - const char *level = NULL; - struct passwd pwstorage, *pwent = NULL; unsigned int i; - long rbuflen; - char *rbuf = NULL; int retval; *errors = 0; @@ -831,82 +1062,42 @@ static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s, nusers = 0; } + qsort(seuser_list, nseusers, sizeof(semanage_seuser_t *), + &seuser_sort_func); qsort(user_list, nusers, sizeof(semanage_user_t *), (int (*)(const void *, const void *))&user_sort_func); - /* Allocate space for the getpwnam_r buffer */ - rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); - if (rbuflen <= 0) - goto cleanup; - rbuf = malloc(rbuflen); - if (rbuf == NULL) - goto cleanup; - for (i = 0; i < nseusers; i++) { seuname = semanage_seuser_get_sename(seuser_list[i]); name = semanage_seuser_get_name(seuser_list[i]); - if (strcmp(name,"root") && strcmp(seuname, s->fallback_user) == 0) - continue; - if (strcmp(name, DEFAULT_LOGIN) == 0) continue; if (strcmp(name, TEMPLATE_SEUSER) == 0) continue; - /* %groupname syntax */ - if (name[0] == '%') - continue; - /* find the user structure given the name */ u = bsearch(seuname, user_list, nusers, sizeof(semanage_user_t *), (int (*)(const void *, const void *)) &name_user_cmp); - if (u) { - prefix = semanage_user_get_prefix(*u); - level = semanage_user_get_mlslevel(*u); - if (!level) - level = FALLBACK_USER_LEVEL; - } else { - prefix = name; - level = FALLBACK_USER_LEVEL; - } - - retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); - if (retval != 0 || pwent == NULL) { - if (retval != 0 && retval != ENOENT) { - *errors = STATUS_ERR; - goto cleanup; - } - - WARN(s->h_semanage, - "user %s not in password file", name); - continue; - } - int len = strlen(pwent->pw_dir) -1; - for(; len > 0 && pwent->pw_dir[len] == '/'; len--) { - pwent->pw_dir[len] = '\0'; + /* %groupname syntax */ + if (name[0] == '%') { + retval = get_group_users(s, &head, *u, seuname, + name); + } else { + retval = add_user(s, &head, *u, name, + seuname, name); } - if (strcmp(pwent->pw_dir, "/") == 0) { - /* don't relabel / genhomdircon checked to see if root - * was the user and if so, set his home directory to - * /root */ - continue; - } - if (ignore(pwent->pw_dir)) - continue; - if (push_user_entry(&head, name, seuname, - prefix, pwent->pw_dir, level) != STATUS_SUCCESS) { + if (retval != 0) { *errors = STATUS_ERR; - break; + goto cleanup; } } cleanup: - free(rbuf); if (*errors) { for (; head; pop_user_entry(&head)) { /* the pop function takes care of all the cleanup @@ -927,6 +1118,7 @@ static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s, } static int write_gen_home_dir_context(genhomedircon_settings_t * s, FILE * out, + semanage_list_t * username_context_tpl, semanage_list_t * user_context_tpl, semanage_list_t * homedir_context_tpl) { @@ -939,13 +1131,11 @@ static int write_gen_home_dir_context(genhomedircon_settings_t * s, FILE * out, } for (; users; pop_user_entry(&users)) { - if (write_home_dir_context(s, out, homedir_context_tpl, - users->name, - users->sename, users->home, - users->prefix, users->level)) + if (write_home_dir_context(s, out, homedir_context_tpl, users)) goto err; - if (write_user_context(s, out, user_context_tpl, users->name, - users->sename, users->prefix)) + if (write_username_context(s, out, username_context_tpl, users)) + goto err; + if (write_user_context(s, out, user_context_tpl, users)) goto err; } @@ -968,16 +1158,21 @@ static int write_context_file(genhomedircon_settings_t * s, FILE * out) { semanage_list_t *homedirs = NULL; semanage_list_t *h = NULL; - semanage_list_t *user_context_tpl = NULL; semanage_list_t *homedir_context_tpl = NULL; semanage_list_t *homeroot_context_tpl = NULL; + semanage_list_t *username_context_tpl = NULL; + semanage_list_t *user_context_tpl = NULL; int retval = STATUS_SUCCESS; homedir_context_tpl = make_template(s, &HOME_DIR_PRED); homeroot_context_tpl = make_template(s, &HOME_ROOT_PRED); + username_context_tpl = make_template(s, &USERNAME_CONTEXT_PRED); user_context_tpl = make_template(s, &USER_CONTEXT_PRED); - if (!homedir_context_tpl && !homeroot_context_tpl && !user_context_tpl) + if (!homedir_context_tpl + && !homeroot_context_tpl + && !username_context_tpl + && !user_context_tpl) goto done; if (write_file_context_header(out) != STATUS_SUCCESS) { @@ -1001,19 +1196,19 @@ static int write_context_file(genhomedircon_settings_t * s, FILE * out) for (h = homedirs; h; h = h->next) { Ustr *temp = ustr_dup_cstr(h->data); - if (!temp || !ustr_add_cstr(&temp, "/[^/]*")) { + if (!temp || !ustr_add_cstr(&temp, "/" FALLBACK_NAME)) { ustr_sc_free(&temp); retval = STATUS_ERR; goto done; } - if (write_home_dir_context(s, out, - homedir_context_tpl, - s->fallback_user, s->fallback_user, - ustr_cstr(temp), - s->fallback_user_prefix, s->fallback_user_level) != - STATUS_SUCCESS) { + free(s->fallback->home); + s->fallback->home = (char*) ustr_cstr(temp); + + if (write_home_dir_context(s, out, homedir_context_tpl, + s->fallback) != STATUS_SUCCESS) { ustr_sc_free(&temp); + s->fallback->home = NULL; retval = STATUS_ERR; goto done; } @@ -1021,23 +1216,31 @@ static int write_context_file(genhomedircon_settings_t * s, FILE * out) homeroot_context_tpl, h->data) != STATUS_SUCCESS) { ustr_sc_free(&temp); + s->fallback->home = NULL; retval = STATUS_ERR; goto done; } ustr_sc_free(&temp); + s->fallback->home = NULL; } } - if (user_context_tpl) { + if (user_context_tpl || username_context_tpl) { + if (write_username_context(s, out, username_context_tpl, + s->fallback) != STATUS_SUCCESS) { + retval = STATUS_ERR; + goto done; + } + if (write_user_context(s, out, user_context_tpl, - ".*", s->fallback_user, - s->fallback_user_prefix) != STATUS_SUCCESS) { + s->fallback) != STATUS_SUCCESS) { retval = STATUS_ERR; goto done; } - if (write_gen_home_dir_context(s, out, user_context_tpl, - homedir_context_tpl) != STATUS_SUCCESS) { + if (write_gen_home_dir_context(s, out, username_context_tpl, + user_context_tpl, homedir_context_tpl) + != STATUS_SUCCESS) { retval = STATUS_ERR; } } @@ -1045,6 +1248,7 @@ static int write_context_file(genhomedircon_settings_t * s, FILE * out) done: /* Cleanup */ semanage_list_destroy(&homedirs); + semanage_list_destroy(&username_context_tpl); semanage_list_destroy(&user_context_tpl); semanage_list_destroy(&homedir_context_tpl); semanage_list_destroy(&homeroot_context_tpl); @@ -1068,10 +1272,20 @@ int semanage_genhomedircon(semanage_handle_t * sh, s.fcfilepath = semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS); - s.fallback_user = strdup(FALLBACK_USER); - s.fallback_user_prefix = strdup(FALLBACK_USER_PREFIX); - s.fallback_user_level = strdup(FALLBACK_USER_LEVEL); - if (s.fallback_user == NULL || s.fallback_user_prefix == NULL || s.fallback_user_level == NULL) { + s.fallback = calloc(1, sizeof(genhomedircon_user_entry_t)); + if (s.fallback == NULL) { + retval = STATUS_ERR; + goto done; + } + + s.fallback->name = strdup(FALLBACK_NAME); + s.fallback->sename = strdup(FALLBACK_SENAME); + s.fallback->prefix = strdup(FALLBACK_PREFIX); + s.fallback->level = strdup(FALLBACK_LEVEL); + if (s.fallback->name == NULL + || s.fallback->sename == NULL + || s.fallback->prefix == NULL + || s.fallback->level == NULL) { retval = STATUS_ERR; goto done; } @@ -1095,9 +1309,7 @@ done: if (out != NULL) fclose(out); - free(s.fallback_user); - free(s.fallback_user_prefix); - free(s.fallback_user_level); + pop_user_entry(&(s.fallback)); ignore_free(); return retval; diff --git libsemanage-2.5/src/semanage_store.c libsemanage-2.5/src/semanage_store.c index fa0876f..ca29257 100644 --- libsemanage-2.5/src/semanage_store.c +++ libsemanage-2.5/src/semanage_store.c @@ -292,6 +292,13 @@ static int semanage_init_final_suffix(semanage_handle_t *sh) goto cleanup; } + if (asprintf(&semanage_final_suffix[SEMANAGE_FC_BIN], "%s.bin", + semanage_final_suffix[SEMANAGE_FC]) < 0) { + ERR(sh, "Unable to allocate space for file context path."); + status = -1; + goto cleanup; + } + semanage_final_suffix[SEMANAGE_FC_HOMEDIRS] = strdup(selinux_file_context_homedir_path() + offset); if (semanage_final_suffix[SEMANAGE_FC_HOMEDIRS] == NULL) { @@ -300,6 +307,13 @@ static int semanage_init_final_suffix(semanage_handle_t *sh) goto cleanup; } + if (asprintf(&semanage_final_suffix[SEMANAGE_FC_HOMEDIRS_BIN], "%s.bin", + semanage_final_suffix[SEMANAGE_FC_HOMEDIRS]) < 0) { + ERR(sh, "Unable to allocate space for file context home directory path."); + status = -1; + goto cleanup; + } + semanage_final_suffix[SEMANAGE_FC_LOCAL] = strdup(selinux_file_context_local_path() + offset); if (semanage_final_suffix[SEMANAGE_FC_LOCAL] == NULL) { @@ -308,6 +322,13 @@ static int semanage_init_final_suffix(semanage_handle_t *sh) goto cleanup; } + if (asprintf(&semanage_final_suffix[SEMANAGE_FC_LOCAL_BIN], "%s.bin", + semanage_final_suffix[SEMANAGE_FC_LOCAL]) < 0) { + ERR(sh, "Unable to allocate space for local file context path."); + status = -1; + goto cleanup; + } + semanage_final_suffix[SEMANAGE_NC] = strdup(selinux_netfilter_context_path() + offset); if (semanage_final_suffix[SEMANAGE_NC] == NULL) { @@ -1491,6 +1512,45 @@ static int sefcontext_compile(semanage_handle_t * sh, const char *path) { return 0; } +static int semanage_validate_and_compile_fcontexts(semanage_handle_t * sh) +{ + int status = -1; + + if (sh->do_check_contexts) { + int ret; + ret = semanage_exec_prog( + sh, + sh->conf->setfiles, + semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_KERNEL), + semanage_final_path(SEMANAGE_FINAL_TMP, + SEMANAGE_FC)); + if (ret != 0) { + ERR(sh, "setfiles returned error code %d.", ret); + goto cleanup; + } + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC)) != 0) { + goto cleanup; + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL)) != 0) { + goto cleanup; + } + + if (sefcontext_compile(sh, + semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS)) != 0) { + goto cleanup; + } + + status = 0; +cleanup: + return status; +} + /* Load the contexts of the final tmp into the final selinux directory. * Return 0 on success, -3 on error. */ @@ -1566,35 +1626,6 @@ static int semanage_install_final_tmp(semanage_handle_t * sh) } skip_reload: - if (sh->do_check_contexts) { - ret = semanage_exec_prog( - sh, - sh->conf->setfiles, - semanage_final_path(SEMANAGE_FINAL_SELINUX, - SEMANAGE_KERNEL), - semanage_final_path(SEMANAGE_FINAL_SELINUX, - SEMANAGE_FC)); - if (ret != 0) { - ERR(sh, "setfiles returned error code %d.", ret); - goto cleanup; - } - } - - if (sefcontext_compile(sh, - semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC)) != 0) { - goto cleanup; - } - - if (sefcontext_compile(sh, - semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC_LOCAL)) != 0) { - goto cleanup; - } - - if (sefcontext_compile(sh, - semanage_final_path(SEMANAGE_FINAL_SELINUX, SEMANAGE_FC_HOMEDIRS)) != 0) { - goto cleanup; - } - status = 0; cleanup: return status; @@ -1737,6 +1768,9 @@ int semanage_install_sandbox(semanage_handle_t * sh) goto cleanup; } + if (semanage_validate_and_compile_fcontexts(sh) < 0) + goto cleanup; + if ((commit_num = semanage_commit_sandbox(sh)) < 0) { retval = commit_num; goto cleanup; diff --git libsemanage-2.5/src/semanage_store.h libsemanage-2.5/src/semanage_store.h index acb6e3f..c5b33c8 100644 --- libsemanage-2.5/src/semanage_store.h +++ libsemanage-2.5/src/semanage_store.h @@ -71,8 +71,11 @@ enum semanage_final_defs { enum semanage_final_path_defs { SEMANAGE_FINAL_TOPLEVEL, SEMANAGE_FC, + SEMANAGE_FC_BIN, SEMANAGE_FC_HOMEDIRS, + SEMANAGE_FC_HOMEDIRS_BIN, SEMANAGE_FC_LOCAL, + SEMANAGE_FC_LOCAL_BIN, SEMANAGE_KERNEL, SEMANAGE_NC, SEMANAGE_SEUSERS, diff --git libsemanage-2.5/tests/.gitignore libsemanage-2.5/tests/.gitignore new file mode 100644 index 0000000..f07111d --- /dev/null +++ libsemanage-2.5/tests/.gitignore @@ -0,0 +1 @@ +libsemanage-tests diff --git libsemanage-2.5/tests/Makefile libsemanage-2.5/tests/Makefile index fec96ff..4b81fed 100644 --- libsemanage-2.5/tests/Makefile +++ libsemanage-2.5/tests/Makefile @@ -10,7 +10,6 @@ LIBS = ../src/libsemanage.a ../../libselinux/src/libselinux.a ../../libsepol/src ########################################################################### EXECUTABLE = libsemanage-tests -CC = gcc CFLAGS += -g -O0 -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute -Wno-unused-parameter INCLUDE = -I$(TESTSRC) -I$(TESTSRC)/../include LDFLAGS += -lcunit -lustr -lbz2 -laudit diff --git libsemanage-2.5/utils/semanage_migrate_store libsemanage-2.5/utils/semanage_migrate_store index 0ebd285..2bdcc05 100755 --- libsemanage-2.5/utils/semanage_migrate_store +++ libsemanage-2.5/utils/semanage_migrate_store @@ -1,4 +1,4 @@ -#!/usr/bin/python -E +#!/usr/bin/python3 -E from __future__ import print_function @@ -16,7 +16,7 @@ try: import selinux import semanage except: - print("You must install libselinux-python and libsemanage-python before running this tool", file=sys.stderr) + print("You must install libselinux-python3 and libsemanage-python3 before running this tool", file=sys.stderr) exit(1)