Skip to content

Commit

Permalink
added selinux support
Browse files Browse the repository at this point in the history
Commit adds SELinux support to dropbear by:

- adding a new '--enable-selinux' option to configure; by default, it
  is disabled.  This option defines an ENABLE_SELINUX preprocessor
  macro.

- mapping the unix username to the SELinux user which is stored in a
  new 'user_sid' attribute in the AuthState object

- relabeling the controlling pty

- setting the context for the next execve() call to the user_sid

Operations above will not be done when SELinux is disabled.  Failures will
generate LOG_ERR messages and in enforcing SELinux mode, dropbear_exit()
will be called.

Signed-off-by: Enrico Scholz <[email protected]>
  • Loading branch information
ensc committed Nov 23, 2018
1 parent df0f129 commit 6f96815
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif

ifeq (@ENABLE_SELINUX@, 1)
LIBS+=-lselinux
CFLAGS+=-DDROPBEAR_ENABLE_SELINUX
endif

OPTION_HEADERS = default_options_guard.h sysoptions.h
ifneq ($(wildcard localoptions.h),)
CFLAGS+=-DLOCALOPTIONS_H_EXISTS
Expand Down
4 changes: 4 additions & 0 deletions auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ struct AuthState {
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
struct PubKeyOptions* pubkey_options;
#endif

#ifdef DROPBEAR_ENABLE_SELINUX
char *user_sid;
#endif
};

#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
Expand Down
11 changes: 11 additions & 0 deletions common-session.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
#include "runopts.h"
#include "netio.h"

#if DROPBEAR_ENABLE_SELINUX
# include <selinux/selinux.h>
# include <selinux/get_context_list.h>
#endif

static void checktimeouts(void);
static long select_timeout(void);
static int ident_readln(int fd, char* buf, int count);
Expand Down Expand Up @@ -318,6 +323,10 @@ void session_cleanup() {
}
#endif

#if DROPBEAR_ENABLE_SELINUX
freecon(ses.authstate.user_sid);
#endif

m_free(ses.remoteident);
m_free(ses.authstate.pw_dir);
m_free(ses.authstate.pw_name);
Expand Down Expand Up @@ -595,6 +604,7 @@ const char* get_user_shell() {
return ses.authstate.pw_shell;
}
}

void fill_passwd(const char* username) {
struct passwd *pw = NULL;
if (ses.authstate.pw_name)
Expand All @@ -615,6 +625,7 @@ void fill_passwd(const char* username) {
ses.authstate.pw_name = m_strdup(pw->pw_name);
ses.authstate.pw_dir = m_strdup(pw->pw_dir);
ses.authstate.pw_shell = m_strdup(pw->pw_shell);

{
char *passwd_crypt = pw->pw_passwd;
#ifdef HAVE_SHADOW_H
Expand Down
8 changes: 8 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,14 @@ AC_ARG_WITH(lastlog,
fi
]
)
AC_ARG_ENABLE([selinux],
[ --enable-selinux Enable SELinux support],
[
if test "x$enableval" = "xyes" ; then
AC_SUBST([ENABLE_SELINUX],[1])
fi
]
)

if test -z "$no_loginfunc_check"; then
dnl Checks for libutil functions (login(), logout() etc, not openpty() )
Expand Down
41 changes: 41 additions & 0 deletions svr-auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "dbrandom.h"

static int checkusername(const char *username, unsigned int userlen);
static void initselinux(const char *username);

/* initialise the first time for a session, resetting all parameters */
void svr_authinitialise() {
Expand Down Expand Up @@ -119,6 +120,8 @@ void recv_msg_userauth_request() {
valid_user = 1;
}

initselinux(ses.authstate.pw_name);

/* user wants to know what methods are supported */
if (methodlen == AUTH_METHOD_NONE_LEN &&
strncmp(methodname, AUTH_METHOD_NONE,
Expand Down Expand Up @@ -227,6 +230,44 @@ static int check_group_membership(gid_t check_gid, const char* username, gid_t u
}
#endif

static void initselinux(const char *username)
{
#ifdef DROPBEAR_ENABLE_SELINUX
char *seuser;
char *level;
int rc;

if (!is_selinux_enabled())
return 0;

freecon(ses.authstate.user_sid);
ses.authstate.user_sid = NULL;

rc = getseuserbyname(username, &seuser, &level);
if (rc < 0) {
dropbear_log(LOG_ERR, "getseuserbyname(%s) failed", username);
goto out;
}

rc = get_default_context_with_level(seuser, level, NULL,
&ses.authstate.user_sid);
free(seuser);
free(level);

if (rc < 0) {
dropbear_log(LOG_ERR, "get_default_context(%s) failed", username);
ses.authstate.user_sid = NULL;
goto out;
}

rc = 0;

out:
if (rc < 0 && security_getenforce() > 0)
dropbear_exit("SELinux: failed to initialie");
#endif
}

/* Check that the username exists and isn't disallowed (root), and has a valid shell.
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
static int checkusername(const char *username, unsigned int userlen) {
Expand Down
79 changes: 79 additions & 0 deletions svr-chansession.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
#include "runopts.h"
#include "auth.h"

#ifdef DROPBEAR_ENABLE_SELINUX
# include <selinux/selinux.h>
#endif

/* Handles sessions (either shells or programs) requested by the client */

static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
Expand Down Expand Up @@ -573,6 +577,53 @@ static void get_termmodes(const struct ChanSess *chansess) {
TRACE(("leave get_termmodes"))
}

static void relabelpty(const char *tty)
{
#ifdef DROPBEAR_ENABLE_SELINUX
char *old_sid = NULL;
char *new_sid = NULL;
security_class_t class;
int rc;

if (!is_selinux_enabled())
return;

rc = getfilecon(tty, &old_sid);
if (rc < 0) {
dropbear_log(LOG_ERR, "failed to get context of tty '%s'", tty);
goto out;
}

class = string_to_security_class("chr_file");
if (!class) {
rc = -1;
dropbear_log(LOG_ERR, "SELinux: failed to map 'chr_file'");
goto out;
}

rc = security_compute_relabel(ses.authstate.user_sid, old_sid, class, &new_sid);
if (rc < 0) {
dropbear_log(LOG_ERR, "failed to compute tty relabel");
goto out;
}

rc = setfilecon(tty, new_sid);
if (rc < 0) {
dropbear_log(LOG_ERR, "failed to set file context for '%s'", tty);
goto out;
}

rc = 0;

out:
freecon(new_sid);
freecon(old_sid);

if (rc < 0 && security_getenforce() > 0)
dropbear_exit("SELinux: failed to relabel PTY");
#endif
}

/* Set up a session pty which will be used to execute the shell or program.
* The pty is allocated now, and kept for when the shell/program executes.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
Expand Down Expand Up @@ -621,6 +672,8 @@ static int sessionpty(struct ChanSess * chansess) {
/* Read the terminal modes */
get_termmodes(chansess);

relabelpty(chansess->tty);

TRACE(("leave sessionpty"))
return DROPBEAR_SUCCESS;
}
Expand Down Expand Up @@ -743,6 +796,30 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
return ret;
}

static void init_selinux_session(void)
{
#ifdef DROPBEAR_ENABLE_SELINUX
char *ctx = ses.authstate.user_sid;
int rc;
unsigned int i;

if (!is_selinux_enabled())
return;

rc = setexeccon(ctx);
if (rc < 0) {
dropbear_log(LOG_ERR, "setexeccon() failed");
goto out;
}

rc = 0;

out:
if (rc < 0 && security_getenforce() > 0)
dropbear_exit("SELinux: failed to initialize session");
#endif
}

/* Execute a command and set up redirection of stdin/stdout/stderr without a
* pty.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
Expand Down Expand Up @@ -949,6 +1026,8 @@ static void execchild(const void *user_data) {
#endif /* HAVE_CLEARENV */
#endif /* DEBUG_VALGRIND */

init_selinux_session();

/* We can only change uid/gid as root ... */
if (getuid() == 0) {

Expand Down

0 comments on commit 6f96815

Please sign in to comment.