Integrate the functionality from runscript_selinux.so
runscript used to dlopen() runscript_selinux.so. This adds equivalent functionality directly in to runscript instead. It authenticates with either PAM or shadow and optionally has a dep on audit. X-Gentoo-Bug: 517450 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=517450
This commit is contained in:
parent
be952bebb3
commit
1932360adc
@ -9,6 +9,19 @@ LIBDL= -Wl,-Bdynamic -ldl
|
|||||||
|
|
||||||
ifeq (${MKSELINUX},yes)
|
ifeq (${MKSELINUX},yes)
|
||||||
CPPFLAGS+= -DHAVE_SELINUX
|
CPPFLAGS+= -DHAVE_SELINUX
|
||||||
LIBSELINUX= -lselinux
|
LIBSELINUX?= -lselinux
|
||||||
LDADD += $(LIBSELINUX)
|
LDADD += $(LIBSELINUX)
|
||||||
|
|
||||||
|
ifneq (${MKPAM},pam)
|
||||||
|
# if using selinux but not pam then we need crypt
|
||||||
|
LIBCRYPT?= -lcrypt
|
||||||
|
LDADD += $(LIBCRYPT)
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq (${MKAUDIT},yes)
|
||||||
|
LIBAUDIT?= -laudit
|
||||||
|
CPPFLAGS+= -DHAVE_AUDIT
|
||||||
|
LDADD+= ${LIBAUDIT}
|
||||||
endif
|
endif
|
||||||
|
@ -3,6 +3,12 @@ LIBPAM?= -lpam
|
|||||||
CPPFLAGS+= -DHAVE_PAM
|
CPPFLAGS+= -DHAVE_PAM
|
||||||
LDADD+= ${LIBPAM}
|
LDADD+= ${LIBPAM}
|
||||||
|
|
||||||
|
ifeq (${MKSELINUX},yes)
|
||||||
|
# with selinux, pam_misc is needed too
|
||||||
|
LIBPAM_MISC?= -lpam_misc
|
||||||
|
LDADD+= ${LIBPAM_MISC}
|
||||||
|
endif
|
||||||
|
|
||||||
PAMDIR?= /etc/pam.d
|
PAMDIR?= /etc/pam.d
|
||||||
PAMMODE?= 0644
|
PAMMODE?= 0644
|
||||||
else ifneq (${MKPAM},)
|
else ifneq (${MKPAM},)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
rc-selinux.c
|
* rc-selinux.c
|
||||||
SELinux helpers to get and set contexts.
|
* SELinux helpers to get and set contexts.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014 Jason Zaman <jason@perfinion.com>
|
* Copyright (c) 2014 Jason Zaman <jason@perfinion.com>
|
||||||
@ -31,11 +31,18 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <sys/stat.h>
|
#include <limits.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <selinux/selinux.h>
|
#include <selinux/selinux.h>
|
||||||
#include <selinux/label.h>
|
#include <selinux/label.h>
|
||||||
|
#include <selinux/get_default_type.h>
|
||||||
|
#include <selinux/context.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "einfo.h"
|
#include "einfo.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
@ -44,11 +51,28 @@
|
|||||||
#include "rc-plugin.h"
|
#include "rc-plugin.h"
|
||||||
#include "rc-selinux.h"
|
#include "rc-selinux.h"
|
||||||
|
|
||||||
#define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
|
/* the context files for selinux */
|
||||||
|
#define RUN_INIT_FILE "run_init_type"
|
||||||
|
#define INITRC_FILE "initrc_context"
|
||||||
|
|
||||||
static void (*selinux_run_init_old) (void);
|
#ifdef HAVE_AUDIT
|
||||||
static void (*selinux_run_init_new) (int argc, char **argv);
|
#include <libaudit.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* PAM or shadow for authentication */
|
||||||
|
#ifdef HAVE_PAM
|
||||||
|
# define PAM_SERVICE_NAME "run_init" /* the name of this program for PAM */
|
||||||
|
# include <security/pam_appl.h>
|
||||||
|
# include <security/pam_misc.h>
|
||||||
|
#else
|
||||||
|
# define PASSWORD_PROMPT "Password:"
|
||||||
|
# include <crypt.h>
|
||||||
|
# include <shadow.h>
|
||||||
|
# include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* The handle for the fcontext lookups */
|
||||||
static struct selabel_handle *hnd = NULL;
|
static struct selabel_handle *hnd = NULL;
|
||||||
|
|
||||||
int selinux_util_label(const char *path)
|
int selinux_util_label(const char *path)
|
||||||
@ -133,33 +157,243 @@ int selinux_util_close(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void selinux_setup(int argc, char **argv)
|
/*
|
||||||
|
* This will check the users password and return 0 on success or -1 on fail
|
||||||
|
*
|
||||||
|
* We ask for the password to make sure it is intended vs run by malicious software.
|
||||||
|
* Actual authorization is covered by the policy itself.
|
||||||
|
*/
|
||||||
|
static int check_password(char *username)
|
||||||
{
|
{
|
||||||
void *lib_handle = NULL;
|
int ret = 1;
|
||||||
|
#ifdef HAVE_PAM
|
||||||
|
pam_handle_t *pamh;
|
||||||
|
int pam_err = 0;
|
||||||
|
const struct pam_conv pconv = {
|
||||||
|
misc_conv,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
if (!exists(SELINUX_LIB))
|
pam_err = pam_start(PAM_SERVICE_NAME, username, &pconv, &pamh);
|
||||||
return;
|
if (pam_err != PAM_SUCCESS) {
|
||||||
|
ret = -1;
|
||||||
|
goto outpam;
|
||||||
|
}
|
||||||
|
|
||||||
lib_handle = dlopen(SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
|
pam_err = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK);
|
||||||
if (!lib_handle) {
|
if (pam_err != PAM_SUCCESS) {
|
||||||
eerror("dlopen: %s", dlerror());
|
ret = -1;
|
||||||
|
goto outpam;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
outpam:
|
||||||
|
pam_end(pamh, pam_err);
|
||||||
|
pamh = NULL;
|
||||||
|
|
||||||
|
#else /* authenticating via /etc/shadow instead */
|
||||||
|
struct spwd *spw;
|
||||||
|
char *password;
|
||||||
|
char *attempt;
|
||||||
|
|
||||||
|
spw = getspnam(username);
|
||||||
|
if (!spw) {
|
||||||
|
eerror("Failed to read shadow entry");
|
||||||
|
ret = -1;
|
||||||
|
goto outshadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
attempt = getpass(PASSWORD_PROMPT);
|
||||||
|
if (!attempt) {
|
||||||
|
ret = -1;
|
||||||
|
goto outshadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*spw->sp_pwdp == '\0' && *attempt == '\0') {
|
||||||
|
ret = -1;
|
||||||
|
goto outshadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* salt must be at least two characters long */
|
||||||
|
if (!(spw->sp_pwdp[0] && spw->sp_pwdp[1])) {
|
||||||
|
ret = -1;
|
||||||
|
goto outshadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encrypt the password attempt */
|
||||||
|
password = crypt(attempt, spw->sp_pwdp);
|
||||||
|
|
||||||
|
if (password && strcmp(password, spw->sp_pwdp) == 0)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
ret = -1;
|
||||||
|
outshadow:
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Authenticates the user, returns 0 on success, 1 on fail */
|
||||||
|
static int check_auth()
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
|
#ifdef HAVE_AUDIT
|
||||||
|
uid = audit_getloginuid();
|
||||||
|
if (uid == (uid_t) -1)
|
||||||
|
uid = getuid();
|
||||||
|
#else
|
||||||
|
uid = getuid();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pw = getpwuid(uid);
|
||||||
|
if (!pw) {
|
||||||
|
eerror("cannot find your entry in the passwd file.");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Authenticating %s.\n", pw->pw_name);
|
||||||
|
|
||||||
|
/* do the actual check */
|
||||||
|
if (check_password(pw->pw_name) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
eerrorx("Authentication failed for %s", pw->pw_name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the context from the given context file. context must be free'd by the user.
|
||||||
|
*/
|
||||||
|
static int read_context_file(const char *filename, char **context)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
FILE *fp;
|
||||||
|
char filepath[PATH_MAX];
|
||||||
|
char *line = NULL;
|
||||||
|
char *p;
|
||||||
|
char *p2;
|
||||||
|
size_t len = 0;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
memset(filepath, '\0', PATH_MAX);
|
||||||
|
snprintf(filepath, PATH_MAX - 1, "%s/%s", selinux_contexts_path(), filename);
|
||||||
|
|
||||||
|
fp = fopen(filepath, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
eerror("Failed to open context file: %s", filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((read = getline(&line, &len, fp)) != -1) {
|
||||||
|
/* cut off spaces before the string */
|
||||||
|
p = line;
|
||||||
|
while (isspace(*p) && *p != '\0')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
/* empty string, skip */
|
||||||
|
if (*p == '\0')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* cut off spaces after the string */
|
||||||
|
p2 = p;
|
||||||
|
while (!isspace(*p2) && *p2 != '\0')
|
||||||
|
p2++;
|
||||||
|
*p2 = '\0';
|
||||||
|
|
||||||
|
*context = xstrdup(p);
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
fclose(fp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void selinux_setup(char **argv)
|
||||||
|
{
|
||||||
|
char *new_context = NULL;
|
||||||
|
char *curr_context = NULL;
|
||||||
|
context_t curr_con;
|
||||||
|
char *curr_t = NULL;
|
||||||
|
char *run_init_t = NULL;
|
||||||
|
|
||||||
|
/* Return, if selinux is disabled. */
|
||||||
|
if (is_selinux_enabled() < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
selinux_run_init_old = (void (*)(void))
|
if (read_context_file(RUN_INIT_FILE, &run_init_t) != 0) {
|
||||||
dlfunc(lib_handle, "selinux_runscript");
|
/* assume a reasonable default, rather than bailing out */
|
||||||
selinux_run_init_new = (void (*)(int, char **))
|
run_init_t = xstrdup("run_init_t");
|
||||||
dlfunc(lib_handle, "selinux_runscript2");
|
ewarn("Assuming SELinux run_init type is %s", run_init_t);
|
||||||
|
}
|
||||||
|
|
||||||
/* Use new run_init if it exists, else fall back to old */
|
/* Get our current context. */
|
||||||
if (selinux_run_init_new)
|
if (getcon(&curr_context) < 0) {
|
||||||
selinux_run_init_new(argc, argv);
|
if (errno == ENOENT) {
|
||||||
else if (selinux_run_init_old)
|
/* should only hit this if proc is not mounted. this
|
||||||
selinux_run_init_old();
|
* happens on Gentoo right after init starts, when
|
||||||
else
|
* the init script processing starts.
|
||||||
/* This shouldnt happen... probably corrupt lib */
|
*/
|
||||||
eerrorx
|
goto out;
|
||||||
("run_init is missing from runscript_selinux.so!");
|
} else {
|
||||||
|
perror("getcon");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dlclose(lib_handle);
|
/* extract the type from the context */
|
||||||
|
curr_con = context_new(curr_context);
|
||||||
|
curr_t = xstrdup(context_type_get(curr_con));
|
||||||
|
/* dont need them anymore so free() now */
|
||||||
|
context_free(curr_con);
|
||||||
|
free(curr_context);
|
||||||
|
|
||||||
|
/* if we are not in the run_init domain, we should not do anything */
|
||||||
|
if (strncmp(run_init_t, curr_t, strlen(run_init_t)) != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(curr_t);
|
||||||
|
free(run_init_t);
|
||||||
|
|
||||||
|
if (check_auth() != 0) {
|
||||||
|
eerrorx("Authentication failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the context for the script to be run in. */
|
||||||
|
if (read_context_file(INITRC_FILE, &new_context) != 0) {
|
||||||
|
/* assume a reasonable default, rather than bailing out */
|
||||||
|
new_context = xstrdup("system_u:system_r:initrc_t");
|
||||||
|
ewarn("Assuming SELinux initrc context is %s", new_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the new context */
|
||||||
|
if (setexeccon(new_context) < 0) {
|
||||||
|
eerrorx("Could not set SELinux exec context to %s.", new_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(new_context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* exec will recycle ptys so try and use open_init_pty if it exists
|
||||||
|
* which will open the pty with initrc_devpts_t, if it doesnt exist,
|
||||||
|
* fall back to plain exec
|
||||||
|
*/
|
||||||
|
if (access("/usr/sbin/open_init_pty", X_OK)) {
|
||||||
|
if (execvp("/usr/sbin/open_init_pty", argv)) {
|
||||||
|
perror("execvp");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
} else if (execvp(argv[1], argv + 1)) {
|
||||||
|
perror("execvp");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(run_init_t);
|
||||||
|
free(curr_t);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,6 @@ int selinux_util_open(void);
|
|||||||
int selinux_util_label(const char *path);
|
int selinux_util_label(const char *path);
|
||||||
int selinux_util_close(void);
|
int selinux_util_close(void);
|
||||||
|
|
||||||
void selinux_setup(int argc, char **argv);
|
void selinux_setup(char **argv);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1193,7 +1193,7 @@ openrc_run(int argc, char **argv)
|
|||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
/* Ok, we are ready to go, so setup selinux if applicable */
|
/* Ok, we are ready to go, so setup selinux if applicable */
|
||||||
selinux_setup(argc, argv);
|
selinux_setup(argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
deps = true;
|
deps = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user