Skip to content

Commit 6f96815

Browse files
committed
added selinux support
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]>
1 parent df0f129 commit 6f96815

File tree

6 files changed

+148
-0
lines changed

6 files changed

+148
-0
lines changed

Makefile.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
2424
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
2525
endif
2626

27+
ifeq (@ENABLE_SELINUX@, 1)
28+
LIBS+=-lselinux
29+
CFLAGS+=-DDROPBEAR_ENABLE_SELINUX
30+
endif
31+
2732
OPTION_HEADERS = default_options_guard.h sysoptions.h
2833
ifneq ($(wildcard localoptions.h),)
2934
CFLAGS+=-DLOCALOPTIONS_H_EXISTS

auth.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ struct AuthState {
127127
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
128128
struct PubKeyOptions* pubkey_options;
129129
#endif
130+
131+
#ifdef DROPBEAR_ENABLE_SELINUX
132+
char *user_sid;
133+
#endif
130134
};
131135

132136
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT

common-session.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
#include "runopts.h"
3737
#include "netio.h"
3838

39+
#if DROPBEAR_ENABLE_SELINUX
40+
# include <selinux/selinux.h>
41+
# include <selinux/get_context_list.h>
42+
#endif
43+
3944
static void checktimeouts(void);
4045
static long select_timeout(void);
4146
static int ident_readln(int fd, char* buf, int count);
@@ -318,6 +323,10 @@ void session_cleanup() {
318323
}
319324
#endif
320325

326+
#if DROPBEAR_ENABLE_SELINUX
327+
freecon(ses.authstate.user_sid);
328+
#endif
329+
321330
m_free(ses.remoteident);
322331
m_free(ses.authstate.pw_dir);
323332
m_free(ses.authstate.pw_name);
@@ -595,6 +604,7 @@ const char* get_user_shell() {
595604
return ses.authstate.pw_shell;
596605
}
597606
}
607+
598608
void fill_passwd(const char* username) {
599609
struct passwd *pw = NULL;
600610
if (ses.authstate.pw_name)
@@ -615,6 +625,7 @@ void fill_passwd(const char* username) {
615625
ses.authstate.pw_name = m_strdup(pw->pw_name);
616626
ses.authstate.pw_dir = m_strdup(pw->pw_dir);
617627
ses.authstate.pw_shell = m_strdup(pw->pw_shell);
628+
618629
{
619630
char *passwd_crypt = pw->pw_passwd;
620631
#ifdef HAVE_SHADOW_H

configure.ac

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,14 @@ AC_ARG_WITH(lastlog,
610610
fi
611611
]
612612
)
613+
AC_ARG_ENABLE([selinux],
614+
[ --enable-selinux Enable SELinux support],
615+
[
616+
if test "x$enableval" = "xyes" ; then
617+
AC_SUBST([ENABLE_SELINUX],[1])
618+
fi
619+
]
620+
)
613621

614622
if test -z "$no_loginfunc_check"; then
615623
dnl Checks for libutil functions (login(), logout() etc, not openpty() )

svr-auth.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "dbrandom.h"
3939

4040
static int checkusername(const char *username, unsigned int userlen);
41+
static void initselinux(const char *username);
4142

4243
/* initialise the first time for a session, resetting all parameters */
4344
void svr_authinitialise() {
@@ -119,6 +120,8 @@ void recv_msg_userauth_request() {
119120
valid_user = 1;
120121
}
121122

123+
initselinux(ses.authstate.pw_name);
124+
122125
/* user wants to know what methods are supported */
123126
if (methodlen == AUTH_METHOD_NONE_LEN &&
124127
strncmp(methodname, AUTH_METHOD_NONE,
@@ -227,6 +230,44 @@ static int check_group_membership(gid_t check_gid, const char* username, gid_t u
227230
}
228231
#endif
229232

233+
static void initselinux(const char *username)
234+
{
235+
#ifdef DROPBEAR_ENABLE_SELINUX
236+
char *seuser;
237+
char *level;
238+
int rc;
239+
240+
if (!is_selinux_enabled())
241+
return 0;
242+
243+
freecon(ses.authstate.user_sid);
244+
ses.authstate.user_sid = NULL;
245+
246+
rc = getseuserbyname(username, &seuser, &level);
247+
if (rc < 0) {
248+
dropbear_log(LOG_ERR, "getseuserbyname(%s) failed", username);
249+
goto out;
250+
}
251+
252+
rc = get_default_context_with_level(seuser, level, NULL,
253+
&ses.authstate.user_sid);
254+
free(seuser);
255+
free(level);
256+
257+
if (rc < 0) {
258+
dropbear_log(LOG_ERR, "get_default_context(%s) failed", username);
259+
ses.authstate.user_sid = NULL;
260+
goto out;
261+
}
262+
263+
rc = 0;
264+
265+
out:
266+
if (rc < 0 && security_getenforce() > 0)
267+
dropbear_exit("SELinux: failed to initialie");
268+
#endif
269+
}
270+
230271
/* Check that the username exists and isn't disallowed (root), and has a valid shell.
231272
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
232273
static int checkusername(const char *username, unsigned int userlen) {

svr-chansession.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
#include "runopts.h"
3939
#include "auth.h"
4040

41+
#ifdef DROPBEAR_ENABLE_SELINUX
42+
# include <selinux/selinux.h>
43+
#endif
44+
4145
/* Handles sessions (either shells or programs) requested by the client */
4246

4347
static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
@@ -573,6 +577,53 @@ static void get_termmodes(const struct ChanSess *chansess) {
573577
TRACE(("leave get_termmodes"))
574578
}
575579

580+
static void relabelpty(const char *tty)
581+
{
582+
#ifdef DROPBEAR_ENABLE_SELINUX
583+
char *old_sid = NULL;
584+
char *new_sid = NULL;
585+
security_class_t class;
586+
int rc;
587+
588+
if (!is_selinux_enabled())
589+
return;
590+
591+
rc = getfilecon(tty, &old_sid);
592+
if (rc < 0) {
593+
dropbear_log(LOG_ERR, "failed to get context of tty '%s'", tty);
594+
goto out;
595+
}
596+
597+
class = string_to_security_class("chr_file");
598+
if (!class) {
599+
rc = -1;
600+
dropbear_log(LOG_ERR, "SELinux: failed to map 'chr_file'");
601+
goto out;
602+
}
603+
604+
rc = security_compute_relabel(ses.authstate.user_sid, old_sid, class, &new_sid);
605+
if (rc < 0) {
606+
dropbear_log(LOG_ERR, "failed to compute tty relabel");
607+
goto out;
608+
}
609+
610+
rc = setfilecon(tty, new_sid);
611+
if (rc < 0) {
612+
dropbear_log(LOG_ERR, "failed to set file context for '%s'", tty);
613+
goto out;
614+
}
615+
616+
rc = 0;
617+
618+
out:
619+
freecon(new_sid);
620+
freecon(old_sid);
621+
622+
if (rc < 0 && security_getenforce() > 0)
623+
dropbear_exit("SELinux: failed to relabel PTY");
624+
#endif
625+
}
626+
576627
/* Set up a session pty which will be used to execute the shell or program.
577628
* The pty is allocated now, and kept for when the shell/program executes.
578629
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
@@ -621,6 +672,8 @@ static int sessionpty(struct ChanSess * chansess) {
621672
/* Read the terminal modes */
622673
get_termmodes(chansess);
623674

675+
relabelpty(chansess->tty);
676+
624677
TRACE(("leave sessionpty"))
625678
return DROPBEAR_SUCCESS;
626679
}
@@ -743,6 +796,30 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
743796
return ret;
744797
}
745798

799+
static void init_selinux_session(void)
800+
{
801+
#ifdef DROPBEAR_ENABLE_SELINUX
802+
char *ctx = ses.authstate.user_sid;
803+
int rc;
804+
unsigned int i;
805+
806+
if (!is_selinux_enabled())
807+
return;
808+
809+
rc = setexeccon(ctx);
810+
if (rc < 0) {
811+
dropbear_log(LOG_ERR, "setexeccon() failed");
812+
goto out;
813+
}
814+
815+
rc = 0;
816+
817+
out:
818+
if (rc < 0 && security_getenforce() > 0)
819+
dropbear_exit("SELinux: failed to initialize session");
820+
#endif
821+
}
822+
746823
/* Execute a command and set up redirection of stdin/stdout/stderr without a
747824
* pty.
748825
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
@@ -949,6 +1026,8 @@ static void execchild(const void *user_data) {
9491026
#endif /* HAVE_CLEARENV */
9501027
#endif /* DEBUG_VALGRIND */
9511028

1029+
init_selinux_session();
1030+
9521031
/* We can only change uid/gid as root ... */
9531032
if (getuid() == 0) {
9541033

0 commit comments

Comments
 (0)