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 4a2bcf8
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 2 deletions.
6 changes: 4 additions & 2 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif

LIBSELINUX_LIBS=@LIBSELINUX_LIBS@

OPTION_HEADERS = default_options_guard.h sysoptions.h
ifneq ($(wildcard localoptions.h),)
CFLAGS+=-DLOCALOPTIONS_H_EXISTS
Expand Down Expand Up @@ -189,7 +191,7 @@ dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)

dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBSELINUX_LIBS) $(LIBS) @CRYPTLIB@

dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
Expand All @@ -210,7 +212,7 @@ ifeq ($(MULTI),1)
endif

dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBSELINUX_LIBS) $(LIBS) @CRYPTLIB@

multibinary: dropbearmulti$(EXEEXT)

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
4 changes: 4 additions & 0 deletions common-session.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ void common_session_init(int sock_in, int sock_out) {
ses.keys->trans.zstream = NULL;
#endif

#ifdef DROPBEAR_ENABLE_SELINUX
ses.authstate.user_sid = NULL;
#endif

/* key exchange buffers */
ses.session_id = NULL;
ses.kexhashbuf = NULL;
Expand Down
12 changes: 12 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,18 @@ AC_ARG_WITH(lastlog,
]
)

AC_MSG_CHECKING([whether to enable SELinux])
AC_ARG_ENABLE([selinux],
[ --enable-selinux Enable SELinux support]
)
AC_MSG_RESULT([$enable_selinux])

AC_ARG_VAR([LIBSELINUX_LIBS],[SELinux libraries])
if test x"$enable_selinux" = xyes; then
AC_DEFINE([DROPBEAR_ENABLE_SELINUX],[1],[Enable SELinux support])
AC_SUBST([LIBSELINUX_LIBS],[${LIBSELINUX_LIBS:--lselinux}])
fi

if test -z "$no_loginfunc_check"; then
dnl Checks for libutil functions (login(), logout() etc, not openpty() )
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,1,[Have login() function])])
Expand Down
46 changes: 46 additions & 0 deletions svr-auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@
#include "runopts.h"
#include "dbrandom.h"

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

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 +125,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 +235,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;

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
78 changes: 78 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,29 @@ 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;

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 +1025,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
8 changes: 8 additions & 0 deletions svr-session.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
#include "crypto_desc.h"
#include "fuzz.h"

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

static void svr_remoteclosed(void);
static void svr_algos_initialise(void);

Expand Down Expand Up @@ -84,6 +88,10 @@ svr_session_cleanup(void) {
/* free potential public key options */
svr_pubkey_options_cleanup();

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

m_free(svr_ses.addrstring);
m_free(svr_ses.remotehost);
m_free(svr_ses.childpids);
Expand Down

0 comments on commit 4a2bcf8

Please sign in to comment.