From: Todd C. Miller Date: Sat, 9 Feb 2008 14:30:06 +0000 (+0000) Subject: Add support for SELinux RBAC. Sudoers entries may specify a role and type. X-Git-Tag: SUDO_1_7_0~201 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f2b70188b6657c159a20d2b1ded36b24350b0410;p=sudo Add support for SELinux RBAC. Sudoers entries may specify a role and type. There are also role and type defaults that may be used. To make sure a transition occurs, when using RBAC commands are executed via the new sesh binary. Based on initial changes from Dan Walsh. --- diff --git a/Makefile.in b/Makefile.in index 161398c4f..84c70571d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -61,6 +61,7 @@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ datarootdir = @datarootdir@ mandir = @mandir@ noexecdir = @NOEXECDIR@ @@ -106,7 +107,7 @@ SRCS = alias.c alloc.c check.c closefrom.c def_data.c defaults.c env.c \ pwutil.c set_perms.c sigaction.c snprintf.c strcasecmp.c strerror.c \ strlcat.c strlcpy.c sudo.c sudo_noexec.c sudo_edit.c sudo_nss.c \ testsudoers.c tgetpass.c toke.c toke.l tsgetgrpw.c utimes.c visudo.c \ - zero_bytes.c redblack.c $(AUTH_SRCS) + zero_bytes.c redblack.c selinux.c sesh.c $(AUTH_SRCS) AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \ auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \ @@ -286,6 +287,8 @@ strlcat.o: $(srcdir)/strlcat.c $(srcdir)/compat.h config.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcat.c strlcpy.o: $(srcdir)/strlcpy.c $(srcdir)/compat.h config.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcpy.c +selinux.o: $(srcdir)/selinux.c $(SUDODEP) + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/selinux.c sudo.o: $(srcdir)/sudo.c $(SUDODEP) sudo_usage.h $(srcdir)/interfaces.h $(srcdir)/version.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo.c sudo_edit.o: $(srcdir)/sudo_edit.c $(SUDODEP) @@ -401,8 +404,9 @@ install-binaries: $(PROGS) $(INSTALL) -O $(install_uid) -G $(install_gid) -M 4111 -s sudo $(DESTDIR)$(sudodir)/sudo rm -f $(DESTDIR)$(sudodir)/sudoedit ln $(DESTDIR)$(sudodir)/sudo $(DESTDIR)$(sudodir)/sudoedit - $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0111 -s visudo $(DESTDIR)$(visudodir)/visudo +@SELINUX@ $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0111 -s sesh $(DESTDIR)$(libexecdir)/sesh + install-noexec: sudo_noexec.la $(LIBTOOL) --mode=install $(INSTALL) sudo_noexec.la $(DESTDIR)$(noexecdir) diff --git a/config.h.in b/config.h.in index 7d9d93955..00d91cbd5 100644 --- a/config.h.in +++ b/config.h.in @@ -317,6 +317,9 @@ /* Define to 1 if you use SecurID for authentication. */ #undef HAVE_SECURID +/* Define to 1 to enable SELinux RBAC support. */ +#undef HAVE_SELINUX + /* Define to 1 if you have the `seteuid' function. */ #undef HAVE_SETEUID diff --git a/configure.in b/configure.in index e64526d5e..50428f785 100644 --- a/configure.in +++ b/configure.in @@ -33,6 +33,7 @@ AC_SUBST(SUDOERS_MODE) AC_SUBST(SUDOERS_UID) AC_SUBST(SUDOERS_GID) AC_SUBST(DEV) +AC_SUBST(SELINUX) AC_SUBST(devdir) AC_SUBST(mansectsu) AC_SUBST(mansectform) @@ -42,6 +43,7 @@ AC_SUBST(noexec_file) AC_SUBST(INSTALL_NOEXEC) AC_SUBST(DONT_LEAK_PATH_INFO) AC_SUBST(BSDAUTH_USAGE) +AC_SUBST(SELINUX_USAGE) AC_SUBST(LDAP) AC_SUBST(LOGINCAP_USAGE) dnl @@ -118,6 +120,7 @@ PROGS="sudo visudo" : ${SUDOERS_GID='0'} DEV="#" LDAP="#" +SELINUX="#" AUTH_OBJS= AUTH_REG= AUTH_EXCL= @@ -1146,6 +1149,20 @@ AC_ARG_ENABLE(path_info, esac ], AC_MSG_RESULT(no)) +AC_ARG_WITH(selinux, [ --with-selinux enable SELinux support], +[case $with_selinux in + yes) SELINUX_USAGE="[[-r role]] [[-t type]] " + AC_DEFINE(HAVE_SELINUX) + SUDO_LIBS="${SUDO_LIBS} -lselinux" + SUDO_OBJS="${SUDO_OBJS} selinux.o" + PROGS="${PROGS} sesh" + SELINUX="" + ;; + no) ;; + *) AC_MSG_ERROR(["--with-selinux does not take an argument."]) + ;; +esac]) + dnl dnl If we don't have egrep we can't do anything... dnl @@ -2414,10 +2431,7 @@ dnl dnl Defer setting _PATH_SUDO_NOEXEC until after exec_prefix is set dnl XXX - this is gross! dnl -if test "$with_noexec" != "no"; then - PROGS="${PROGS} sudo_noexec.la" - INSTALL_NOEXEC="install-noexec" - +if test X"$with_noexec" != X"no" -o X"$with_selinux" != X"no"; then oexec_prefix="$exec_prefix" if test "$exec_prefix" = '$(prefix)'; then if test "$prefix" = "NONE"; then @@ -2426,8 +2440,17 @@ if test "$with_noexec" != "no"; then exec_prefix="$prefix" fi fi - eval noexec_file="$with_noexec" - AC_DEFINE_UNQUOTED(_PATH_SUDO_NOEXEC, "$noexec_file", [The fully qualified pathname of sudo_noexec.so]) + if test X"$with_noexec" != X"no"; then + PROGS="${PROGS} sudo_noexec.la" + INSTALL_NOEXEC="install-noexec" + + eval noexec_file="$with_noexec" + AC_DEFINE_UNQUOTED(_PATH_SUDO_NOEXEC, "$noexec_file", [The fully qualified pathname of sudo_noexec.so]) + fi + if test X"$with_selinux" != X"no"; then + eval sesh_file="$libexecdir/sesh" + AC_DEFINE_UNQUOTED(_PATH_SUDO_SESH, "$sesh_file", [The fully qualified pathname of sesh]) + fi exec_prefix="$oexec_prefix" fi @@ -2489,6 +2512,7 @@ AH_TEMPLATE(HAVE_OPIE, [Define to 1 if you use NRL OPIE.]) AH_TEMPLATE(HAVE_PAM, [Define to 1 if you use PAM authentication.]) AH_TEMPLATE(HAVE_PROJECT_H, [Define to 1 if you have the header file.]) AH_TEMPLATE(HAVE_SECURID, [Define to 1 if you use SecurID for authentication.]) +AH_TEMPLATE(HAVE_SELINUX, [Define to 1 to enable SELinux RBAC support.]) AH_TEMPLATE(HAVE_SIA, [Define to 1 if you use SIA authentication.]) AH_TEMPLATE(HAVE_SIGACTION_T, [Define to 1 if has the sigaction_t typedef.]) AH_TEMPLATE(HAVE_SKEY, [Define to 1 if you use S/Key.]) diff --git a/def_data.c b/def_data.c index a491266e1..96a2b20a4 100644 --- a/def_data.c +++ b/def_data.c @@ -274,6 +274,14 @@ struct sudo_defs_types sudo_defs_table[] = { "env_keep", T_LIST|T_BOOL, "Environment variables to preserve:", NULL, + }, { + "role", T_STR, + "SELinux role to use in the new security context", + NULL, + }, { + "type", T_STR, + "SELinux type to use in the new security context", + NULL, }, { NULL, 0, NULL } diff --git a/def_data.h b/def_data.h index 6d636360e..5f7c39ff0 100644 --- a/def_data.h +++ b/def_data.h @@ -124,6 +124,10 @@ #define I_ENV_DELETE 61 #define def_env_keep (sudo_defs_table[62].sd_un.list) #define I_ENV_KEEP 62 +#define def_role (sudo_defs_table[63].sd_un.str) +#define I_ROLE 63 +#define def_type (sudo_defs_table[64].sd_un.str) +#define I_TYPE 64 enum def_tupple { never, diff --git a/def_data.in b/def_data.in index 83b643371..4a3c46a4c 100644 --- a/def_data.in +++ b/def_data.in @@ -202,3 +202,9 @@ env_delete env_keep T_LIST|T_BOOL "Environment variables to preserve:" +role + T_STR + "SELinux role to use in the new security context" +type + T_STR + "SELinux type to use in the new security context" diff --git a/gram.c b/gram.c index 6fc79ff2c..ced9a1268 100644 --- a/gram.c +++ b/gram.c @@ -141,11 +141,12 @@ typedef union { struct privilege *privilege; struct sudo_command command; struct cmndtag tag; + struct selinux_info seinfo; char *string; int tok; } YYSTYPE; #endif /* YYSTYPE_DEFINED */ -#line 149 "y.tab.c" +#line 150 "y.tab.c" #define COMMAND 257 #define ALIAS 258 #define DEFVAR 259 @@ -171,6 +172,8 @@ typedef union { #define USERALIAS 279 #define RUNASALIAS 280 #define ERROR 281 +#define TYPE 282 +#define ROLE 283 #define YYERRCODE 256 #if defined(__cplusplus) || defined(__STDC__) const short yylhs[] = @@ -178,15 +181,16 @@ const short yylhs[] = short yylhs[] = #endif { -1, - 0, 0, 22, 22, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 4, 4, 3, 3, + 0, 0, 25, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 4, 4, 3, 3, 3, 3, 3, 20, 20, 19, 10, 10, 8, 8, - 8, 8, 8, 2, 2, 1, 6, 6, 17, 17, - 18, 18, 18, 21, 21, 21, 21, 21, 21, 21, - 5, 5, 5, 25, 25, 28, 9, 9, 26, 26, - 29, 7, 7, 27, 27, 30, 24, 24, 31, 13, - 13, 11, 11, 12, 12, 12, 12, 12, 16, 16, - 14, 14, 15, 15, 15, + 8, 8, 8, 2, 2, 1, 6, 6, 23, 24, + 22, 22, 22, 22, 22, 17, 17, 18, 18, 18, + 21, 21, 21, 21, 21, 21, 21, 5, 5, 5, + 28, 28, 31, 9, 9, 29, 29, 32, 7, 7, + 30, 30, 33, 27, 27, 34, 13, 13, 11, 11, + 12, 12, 12, 12, 12, 16, 16, 14, 14, 15, + 15, 15, }; #if defined(__cplusplus) || defined(__STDC__) const short yylen[] = @@ -197,12 +201,13 @@ short yylen[] = 0, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 1, 3, 1, 2, 3, 3, 3, 1, 3, 3, 1, 2, 1, 1, - 1, 1, 1, 1, 3, 3, 1, 2, 0, 3, - 1, 3, 2, 0, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 3, 3, 1, 3, 1, 3, - 3, 1, 3, 1, 3, 3, 1, 3, 3, 1, - 3, 1, 2, 1, 1, 1, 1, 1, 1, 3, - 1, 2, 1, 1, 1, + 1, 1, 1, 1, 3, 4, 1, 2, 3, 3, + 0, 1, 1, 2, 2, 0, 3, 1, 3, 2, + 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, + 1, 3, 3, 1, 3, 1, 3, 3, 1, 3, + 1, 3, 3, 1, 3, 3, 1, 3, 1, 2, + 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, + 1, 1, }; #if defined(__cplusplus) || defined(__STDC__) const short yydefred[] = @@ -210,20 +215,21 @@ const short yydefred[] = short yydefred[] = #endif { 0, - 0, 74, 76, 77, 78, 0, 0, 0, 0, 0, - 75, 5, 0, 0, 0, 0, 0, 0, 70, 72, + 0, 81, 83, 84, 85, 0, 0, 0, 0, 0, + 82, 5, 0, 0, 0, 0, 0, 0, 77, 79, 0, 0, 3, 6, 0, 0, 17, 0, 29, 32, - 31, 33, 30, 0, 27, 0, 57, 0, 0, 53, - 52, 51, 0, 37, 62, 0, 0, 0, 54, 0, - 0, 59, 0, 0, 67, 0, 0, 64, 73, 0, + 31, 33, 30, 0, 27, 0, 64, 0, 0, 60, + 59, 58, 0, 37, 69, 0, 0, 0, 61, 0, + 0, 66, 0, 0, 74, 0, 0, 71, 80, 0, 0, 24, 0, 4, 0, 0, 0, 20, 0, 28, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 71, 0, 0, 21, 22, - 23, 18, 58, 63, 0, 55, 0, 60, 0, 68, - 0, 65, 0, 34, 0, 44, 25, 0, 0, 0, - 0, 0, 83, 85, 84, 0, 79, 81, 0, 0, - 40, 35, 45, 46, 47, 48, 49, 50, 36, 82, - 0, 0, 80, + 0, 0, 0, 0, 0, 78, 0, 0, 21, 22, + 23, 18, 65, 70, 0, 62, 0, 67, 0, 75, + 0, 72, 0, 34, 0, 0, 25, 0, 0, 0, + 0, 0, 0, 51, 0, 0, 90, 92, 91, 0, + 86, 88, 0, 0, 47, 35, 0, 0, 0, 44, + 45, 89, 0, 0, 40, 39, 52, 53, 54, 55, + 56, 57, 36, 87, }; #if defined(__cplusplus) || defined(__STDC__) const short yydgoto[] = @@ -232,123 +238,125 @@ short yydgoto[] = #endif { 18, 104, 105, 27, 28, 44, 45, 46, 35, 61, 37, - 19, 20, 21, 117, 118, 119, 106, 110, 62, 63, - 112, 22, 23, 54, 48, 51, 57, 49, 52, 58, - 55, + 19, 20, 21, 121, 122, 123, 106, 110, 62, 63, + 129, 114, 115, 116, 22, 23, 54, 48, 51, 57, + 49, 52, 58, 55, }; #if defined(__cplusplus) || defined(__STDC__) const short yysindex[] = #else short yysindex[] = #endif - { -33, - -269, 0, 0, 0, 0, -8, 454, 458, 458, -17, - 0, 0, -249, -247, -241, -231, -243, 0, 0, 0, - 141, -33, 0, 0, -37, -216, 0, -16, 0, 0, - 0, 0, 0, -221, 0, -23, 0, -21, -21, 0, - 0, 0, -244, 0, 0, -11, -14, -1, 0, -6, - 2, 0, 3, 4, 0, 5, 7, 0, 0, 458, - -15, 0, 9, 0, -219, -207, -202, 0, -8, 0, - 454, -16, -16, -16, 0, -17, -16, 454, -249, -17, - -247, 458, -241, 458, -231, 0, 23, 454, 0, 0, - 0, 0, 0, 0, 24, 0, 25, 0, 27, 0, - 27, 0, 217, 0, 28, 0, 0, -3, -9, 29, - 23, 250, 0, 0, 0, -222, 0, 0, 30, -3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -3, 30, 0,}; + { 405, + -266, 0, 0, 0, 0, -9, 463, 510, 510, -2, + 0, 0, -243, -218, -215, -211, -225, 0, 0, 0, + -28, 405, 0, 0, -36, -210, 0, 4, 0, 0, + 0, 0, 0, -231, 0, -33, 0, -25, -25, 0, + 0, 0, -240, 0, 0, -21, -6, -1, 0, 2, + 6, 0, 7, 8, 0, 9, 11, 0, 0, 510, + -22, 0, 13, 0, -203, -201, -198, 0, -9, 0, + 463, 4, 4, 4, 0, -2, 4, 463, -243, -2, + -218, 510, -215, 510, -211, 0, 27, 463, 0, 0, + 0, 0, 0, 0, 28, 0, 30, 0, 31, 0, + 31, 0, 141, 0, 32, -262, 0, -27, -16, 36, + 27, 18, 19, 0, -200, -202, 0, 0, 0, -217, + 0, 0, 39, -27, 0, 0, -177, -175, 250, 0, + 0, 0, -27, 39, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,}; #if defined(__cplusplus) || defined(__STDC__) const short yyrindex[] = #else short yyrindex[] = #endif - { 73, + { 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 75, 0, 0, 1, 0, 0, 156, 0, 0, + 0, 91, 0, 0, 1, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 181, 0, 0, 206, 0, 0, 237, 0, 0, 274, 0, 0, 0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 0, 326, 352, 378, 0, 0, 430, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 392, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -29, 0, 0, 0, 0, 0, 0, 0, 26, 0, 52, 0, 78, 0, - 104, 0, 0, 0, 130, 0, 0, 0, 39, 0, - 392, 0, 0, 0, 0, 0, 0, 0, 40, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 41, 0,}; + 104, 0, 0, 0, 130, 442, 0, 0, 51, 0, + -29, 0, 0, 0, 461, 485, 0, 0, 0, 0, + 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,}; #if defined(__cplusplus) || defined(__STDC__) const short yygindex[] = #else short yygindex[] = #endif { 0, - -28, 0, 17, 12, 44, -74, 8, 55, -2, 19, - 31, 76, -5, -39, -22, -25, 0, 0, 11, 0, - 0, 0, 74, 0, 0, 0, 0, 18, 20, 15, - 22, + -18, 0, 29, 15, 56, -73, 16, 63, -5, 34, + 40, 84, 5, -31, -17, -15, 0, 0, 24, 0, + 0, 0, -10, -8, 0, 92, 0, 0, 0, 0, + 37, 38, 33, 41, }; -#define YYTABLESIZE 733 +#define YYTABLESIZE 785 #if defined(__cplusplus) || defined(__STDC__) const short yytable[] = #else short yytable[] = #endif - { 17, - 19, 94, 38, 39, 36, 66, 24, 67, 47, 26, - 50, 26, 40, 41, 2, 43, 53, 3, 4, 5, - 71, 26, 60, 65, 26, 56, 56, 69, 71, 116, - 42, 11, 76, 19, 60, 113, 29, 129, 30, 31, - 114, 32, 68, 89, 19, 87, 78, 72, 120, 73, - 74, 61, 115, 33, 80, 90, 79, 77, 56, 81, - 91, 83, 103, 82, 85, 84, 88, 71, 76, 121, - 60, 111, 1, 131, 2, 95, 99, 69, 101, 41, - 43, 42, 122, 56, 61, 92, 75, 97, 70, 93, - 86, 133, 59, 130, 132, 64, 96, 109, 107, 102, - 98, 0, 0, 66, 100, 0, 0, 0, 0, 61, - 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, - 0, 0, 0, 0, 0, 69, 66, 0, 0, 0, + { 26, + 19, 36, 94, 46, 34, 120, 66, 26, 67, 24, + 71, 26, 38, 39, 47, 60, 40, 41, 60, 112, + 113, 71, 76, 26, 65, 63, 29, 60, 30, 31, + 43, 32, 2, 19, 42, 3, 4, 5, 87, 50, + 117, 124, 53, 33, 19, 118, 56, 69, 68, 11, + 72, 68, 73, 74, 78, 143, 79, 119, 63, 89, + 77, 90, 80, 81, 91, 83, 103, 82, 85, 84, + 88, 71, 95, 76, 60, 111, 125, 76, 127, 128, + 113, 112, 133, 63, 68, 135, 99, 136, 101, 1, + 2, 48, 126, 50, 49, 97, 70, 92, 75, 86, + 59, 144, 132, 73, 93, 131, 130, 109, 134, 68, + 76, 107, 0, 64, 0, 96, 0, 102, 98, 0, + 0, 0, 0, 100, 0, 0, 0, 0, 0, 26, + 0, 0, 0, 0, 0, 76, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, - 0, 66, 26, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, - 9, 0, 0, 0, 60, 0, 0, 26, 12, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 73, 26, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 26, 12, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 2, 0, 0, 3, 4, 5, - 6, 7, 8, 9, 10, 25, 8, 25, 10, 40, - 41, 11, 12, 13, 14, 15, 16, 25, 0, 17, - 25, 0, 0, 0, 113, 0, 19, 42, 19, 114, + 0, 0, 0, 0, 0, 25, 0, 46, 46, 29, + 117, 30, 31, 25, 32, 118, 8, 25, 10, 46, + 46, 46, 46, 46, 46, 46, 33, 119, 0, 25, + 0, 0, 46, 46, 40, 41, 19, 0, 19, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 8, - 0, 115, 0, 11, 108, 19, 19, 19, 19, 19, - 19, 56, 43, 56, 0, 0, 56, 56, 56, 56, - 56, 56, 56, 56, 0, 0, 0, 0, 0, 7, - 56, 56, 56, 56, 56, 56, 11, 61, 0, 61, - 0, 0, 61, 61, 61, 61, 61, 61, 61, 61, - 0, 0, 0, 0, 0, 15, 61, 61, 61, 61, - 61, 61, 7, 69, 0, 69, 0, 0, 69, 69, - 69, 69, 69, 69, 69, 69, 0, 0, 0, 0, - 0, 13, 69, 69, 69, 69, 69, 69, 15, 66, - 0, 66, 0, 0, 66, 66, 66, 66, 66, 66, - 66, 66, 0, 0, 0, 0, 0, 14, 66, 66, - 66, 66, 66, 66, 13, 26, 0, 26, 0, 0, - 26, 26, 26, 26, 26, 26, 26, 26, 29, 0, - 30, 31, 0, 32, 26, 26, 26, 26, 26, 26, - 14, 12, 0, 12, 0, 33, 12, 12, 12, 12, - 12, 12, 12, 12, 39, 0, 0, 0, 0, 16, - 12, 12, 12, 12, 12, 12, 9, 0, 9, 0, + 0, 0, 42, 11, 0, 19, 19, 19, 19, 19, + 19, 63, 43, 63, 0, 0, 63, 63, 63, 63, + 63, 63, 63, 63, 0, 0, 0, 0, 0, 7, + 63, 63, 63, 63, 63, 63, 11, 68, 0, 68, + 0, 0, 68, 68, 68, 68, 68, 68, 68, 68, + 0, 0, 0, 0, 0, 15, 68, 68, 68, 68, + 68, 68, 7, 76, 0, 76, 0, 0, 76, 76, + 76, 76, 76, 76, 76, 76, 0, 0, 0, 0, + 0, 13, 76, 76, 76, 76, 76, 76, 15, 73, + 0, 73, 0, 0, 73, 73, 73, 73, 73, 73, + 73, 73, 0, 0, 0, 0, 0, 14, 73, 73, + 73, 73, 73, 73, 13, 26, 0, 26, 0, 0, + 26, 26, 26, 26, 26, 26, 26, 26, 2, 0, + 0, 3, 4, 5, 26, 26, 26, 26, 26, 26, + 14, 12, 0, 12, 0, 11, 12, 12, 12, 12, + 12, 12, 12, 12, 0, 0, 0, 0, 0, 16, + 12, 12, 12, 12, 12, 12, 9, 17, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 10, 16, 10, 0, 0, 10, 10, 10, 10, - 10, 10, 10, 10, 2, 0, 0, 3, 4, 5, - 10, 10, 10, 10, 10, 10, 34, 0, 0, 0, - 17, 11, 8, 0, 8, 0, 0, 8, 8, 8, + 10, 10, 10, 10, 41, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, + 0, 0, 8, 42, 8, 34, 0, 8, 8, 8, 8, 8, 8, 8, 8, 0, 40, 41, 0, 0, - 0, 8, 8, 8, 8, 8, 8, 0, 123, 124, - 125, 126, 127, 128, 42, 0, 0, 0, 0, 11, + 0, 8, 8, 8, 8, 8, 8, 43, 137, 138, + 139, 140, 141, 142, 42, 0, 0, 0, 0, 11, 0, 11, 0, 0, 11, 11, 11, 11, 11, 11, - 11, 11, 0, 0, 0, 0, 0, 0, 11, 11, + 11, 11, 17, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 0, 7, 0, 7, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, @@ -358,16 +366,21 @@ short yytable[] = 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 0, 14, 0, 14, 0, 0, 14, 14, - 14, 14, 14, 14, 14, 14, 0, 0, 39, 39, + 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 0, 0, - 39, 39, 39, 39, 39, 39, 39, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 16, 0, 16, 0, 0, - 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, + 1, 0, 2, 0, 0, 3, 4, 5, 6, 7, + 8, 9, 10, 0, 0, 0, 0, 0, 0, 11, + 12, 13, 14, 15, 16, 16, 0, 16, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, 41, 41, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, - 0, 29, 0, 30, 31, 2, 32, 0, 3, 4, - 5, 0, 0, 0, 0, 0, 0, 0, 33, 0, - 0, 0, 11, + 41, 41, 41, 41, 41, 41, 41, 42, 42, 0, + 29, 0, 30, 31, 0, 32, 0, 0, 0, 42, + 42, 42, 42, 42, 42, 42, 0, 33, 0, 0, + 0, 43, 43, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 43, 43, 43, 43, 43, 43, 43, + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 11, }; #if defined(__cplusplus) || defined(__STDC__) const short yycheck[] = @@ -375,34 +388,34 @@ const short yycheck[] = short yycheck[] = #endif { 33, - 0, 76, 8, 9, 7, 43, 276, 45, 258, 33, - 258, 33, 257, 258, 258, 33, 258, 261, 262, 263, - 44, 33, 44, 61, 33, 0, 258, 44, 44, 33, - 275, 275, 44, 33, 44, 258, 258, 112, 260, 261, - 263, 263, 259, 263, 44, 61, 61, 36, 58, 38, - 39, 0, 275, 275, 61, 263, 58, 46, 33, 58, - 263, 58, 40, 61, 58, 61, 58, 44, 44, 41, - 44, 44, 0, 44, 0, 78, 82, 0, 84, 41, - 41, 41, 111, 58, 33, 69, 43, 80, 34, 71, - 60, 131, 17, 116, 120, 22, 79, 103, 88, 85, - 81, -1, -1, 0, 83, -1, -1, -1, -1, 58, - 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, + 0, 7, 76, 33, 33, 33, 43, 33, 45, 276, + 44, 33, 8, 9, 258, 44, 257, 258, 44, 282, + 283, 44, 44, 33, 61, 0, 258, 44, 260, 261, + 33, 263, 258, 33, 275, 261, 262, 263, 61, 258, + 258, 58, 258, 275, 44, 263, 258, 44, 259, 275, + 36, 0, 38, 39, 61, 129, 58, 275, 33, 263, + 46, 263, 61, 58, 263, 58, 40, 61, 58, 61, + 58, 44, 78, 44, 44, 44, 41, 0, 61, 61, + 283, 282, 44, 58, 33, 263, 82, 263, 84, 0, + 0, 41, 111, 41, 41, 80, 34, 69, 43, 60, + 17, 133, 120, 0, 71, 116, 115, 103, 124, 58, + 33, 88, -1, 22, -1, 79, -1, 85, 81, -1, + -1, -1, -1, 83, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 58, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 58, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, - 0, -1, -1, -1, 44, -1, -1, 58, 33, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, -1, -1, -1, -1, -1, -1, 58, 33, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, - -1, -1, 256, -1, 258, -1, -1, 261, 262, 263, - 264, 265, 266, 267, 268, 259, 0, 259, 33, 257, - 258, 275, 276, 277, 278, 279, 280, 259, -1, 33, - 259, -1, -1, -1, 258, -1, 256, 275, 258, 263, + -1, -1, -1, -1, -1, 259, -1, 257, 258, 258, + 258, 260, 261, 259, 263, 263, 0, 259, 33, 269, + 270, 271, 272, 273, 274, 275, 275, 275, -1, 259, + -1, -1, 282, 283, 257, 258, 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, 33, - -1, 275, -1, 0, 58, 275, 276, 277, 278, 279, + -1, -1, 275, 0, -1, 275, 276, 277, 278, 279, 280, 256, 33, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, 0, 275, 276, 277, 278, 279, 280, 33, 256, -1, 258, @@ -415,21 +428,21 @@ short yycheck[] = 267, 268, -1, -1, -1, -1, -1, 0, 275, 276, 277, 278, 279, 280, 33, 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, 258, -1, - 260, 261, -1, 263, 275, 276, 277, 278, 279, 280, + -1, 261, 262, 263, 275, 276, 277, 278, 279, 280, 33, 256, -1, 258, -1, 275, 261, 262, 263, 264, - 265, 266, 267, 268, 33, -1, -1, -1, -1, 0, - 275, 276, 277, 278, 279, 280, 256, -1, 258, -1, + 265, 266, 267, 268, -1, -1, -1, -1, -1, 0, + 275, 276, 277, 278, 279, 280, 256, 33, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, -1, 275, 276, 277, 278, 279, 280, 256, 33, 258, -1, -1, 261, 262, 263, 264, - 265, 266, 267, 268, 258, -1, -1, 261, 262, 263, - 275, 276, 277, 278, 279, 280, 33, -1, -1, -1, - 33, 275, 256, -1, 258, -1, -1, 261, 262, 263, + 265, 266, 267, 268, 33, -1, -1, -1, -1, -1, + 275, 276, 277, 278, 279, 280, -1, -1, -1, -1, + -1, -1, 256, 33, 258, 33, -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, 257, 258, -1, -1, - -1, 275, 276, 277, 278, 279, 280, -1, 269, 270, + -1, 275, 276, 277, 278, 279, 280, 33, 269, 270, 271, 272, 273, 274, 275, -1, -1, -1, -1, 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, 266, - 267, 268, -1, -1, -1, -1, -1, -1, 275, 276, + 267, 268, 33, -1, -1, -1, -1, -1, 275, 276, 277, 278, 279, 280, -1, 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, -1, 275, 276, 277, 278, 279, 280, @@ -439,22 +452,27 @@ short yycheck[] = -1, -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, -1, 275, 276, 277, 278, 279, 280, -1, 256, -1, 258, -1, -1, 261, 262, - 263, 264, 265, 266, 267, 268, -1, -1, 257, 258, + 263, 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, -1, 275, 276, 277, 278, 279, 280, -1, -1, - 269, 270, 271, 272, 273, 274, 275, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 256, -1, 258, -1, -1, - 261, 262, 263, 264, 265, 266, 267, 268, -1, -1, + 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, + 266, 267, 268, -1, -1, -1, -1, -1, -1, 275, + 276, 277, 278, 279, 280, 256, -1, 258, -1, -1, + 261, 262, 263, 264, 265, 266, 267, 268, 257, 258, -1, -1, -1, -1, 275, 276, 277, 278, 279, 280, - -1, 258, -1, 260, 261, 258, 263, -1, 261, 262, - 263, -1, -1, -1, -1, -1, -1, -1, 275, -1, - -1, -1, 275, + 269, 270, 271, 272, 273, 274, 275, 257, 258, -1, + 258, -1, 260, 261, -1, 263, -1, -1, -1, 269, + 270, 271, 272, 273, 274, 275, -1, 275, -1, -1, + -1, 257, 258, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 269, 270, 271, 272, 273, 274, 275, + -1, -1, -1, -1, -1, -1, -1, 258, -1, -1, + 261, 262, 263, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 275, }; #define YYFINAL 18 #ifndef YYDEBUG #define YYDEBUG 0 #endif -#define YYMAXTOKEN 281 +#define YYMAXTOKEN 283 #if YYDEBUG #if defined(__cplusplus) || defined(__STDC__) const char * const yyname[] = @@ -472,7 +490,7 @@ char *yyname[] = "COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DEFAULTS", "DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","DEFAULTS_CMND","NOPASSWD", "PASSWD","NOEXEC","EXEC","SETENV","NOSETENV","ALL","COMMENT","HOSTALIAS", -"CMNDALIAS","USERALIAS","RUNASALIAS","ERROR", +"CMNDALIAS","USERALIAS","RUNASALIAS","ERROR","TYPE","ROLE", }; #if defined(__cplusplus) || defined(__STDC__) const char * const yyrule[] = @@ -515,9 +533,16 @@ char *yyrule[] = "host : WORD", "cmndspeclist : cmndspec", "cmndspeclist : cmndspeclist ',' cmndspec", -"cmndspec : runasspec cmndtag opcmnd", +"cmndspec : runasspec selinux cmndtag opcmnd", "opcmnd : cmnd", "opcmnd : '!' cmnd", +"rolespec : ROLE '=' WORD", +"typespec : TYPE '=' WORD", +"selinux :", +"selinux : rolespec", +"selinux : typespec", +"selinux : rolespec typespec", +"selinux : typespec rolespec", "runasspec :", "runasspec : '(' runaslist ')'", "runaslist : userlist", @@ -592,7 +617,7 @@ short *yyss; short *yysslim; YYSTYPE *yyvs; int yystacksize; -#line 541 "gram.y" +#line 591 "gram.y" static struct defaults * new_default(var, val, op) char *var; @@ -693,12 +718,26 @@ init_parser(path, quiet) } while ((priv = tq_pop(&us->privileges)) != NULL) { struct member *runasuser = NULL, *runasgroup = NULL; +#ifdef HAVE_SELINUX + char *role = NULL, *type = NULL; +#endif /* HAVE_SELINUX */ while ((m = tq_pop(&priv->hostlist)) != NULL) { efree(m->name); efree(m); } while ((cs = tq_pop(&priv->cmndlist)) != NULL) { +#ifdef HAVE_SELINUX + /* Only free the first instance of a role/type. */ + if (cs->role != role) { + role = cs->role; + efree(cs->role); + } + if (cs->type != type) { + type = cs->type; + efree(cs->type); + } +#endif /* HAVE_SELINUX */ if (tq_last(&cs->runasuserlist) != runasuser) { runasuser = tq_last(&cs->runasuserlist); while ((m = tq_pop(&cs->runasuserlist)) != NULL) { @@ -747,7 +786,7 @@ init_parser(path, quiet) sudolineno = 1; verbose = !quiet; } -#line 699 "y.tab.c" +#line 738 "y.tab.c" /* allocate initial stack or double stack size, up to YYMAXDEPTH */ #if defined(__cplusplus) || defined(__STDC__) static int yygrowstack(void) @@ -950,127 +989,127 @@ yyreduce: switch (yyn) { case 1: -#line 182 "gram.y" +#line 188 "gram.y" { ; } break; case 5: -#line 190 "gram.y" +#line 196 "gram.y" { ; } break; case 6: -#line 193 "gram.y" +#line 199 "gram.y" { yyerrok; } break; case 7: -#line 196 "gram.y" +#line 202 "gram.y" { add_userspec(yyvsp[-1].member, yyvsp[0].privilege); } break; case 8: -#line 199 "gram.y" +#line 205 "gram.y" { ; } break; case 9: -#line 202 "gram.y" +#line 208 "gram.y" { ; } break; case 10: -#line 205 "gram.y" +#line 211 "gram.y" { ; } break; case 11: -#line 208 "gram.y" +#line 214 "gram.y" { ; } break; case 12: -#line 211 "gram.y" +#line 217 "gram.y" { add_defaults(DEFAULTS, NULL, yyvsp[0].defaults); } break; case 13: -#line 214 "gram.y" +#line 220 "gram.y" { add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults); } break; case 14: -#line 217 "gram.y" +#line 223 "gram.y" { add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults); } break; case 15: -#line 220 "gram.y" +#line 226 "gram.y" { add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults); } break; case 16: -#line 223 "gram.y" +#line 229 "gram.y" { add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults); } break; case 18: -#line 229 "gram.y" +#line 235 "gram.y" { list_append(yyvsp[-2].defaults, yyvsp[0].defaults); yyval.defaults = yyvsp[-2].defaults; } break; case 19: -#line 235 "gram.y" +#line 241 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, TRUE); } break; case 20: -#line 238 "gram.y" +#line 244 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, FALSE); } break; case 21: -#line 241 "gram.y" +#line 247 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, TRUE); } break; case 22: -#line 244 "gram.y" +#line 250 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); } break; case 23: -#line 247 "gram.y" +#line 253 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); } break; case 25: -#line 253 "gram.y" +#line 259 "gram.y" { list_append(yyvsp[-2].privilege, yyvsp[0].privilege); yyval.privilege = yyvsp[-2].privilege; } break; case 26: -#line 259 "gram.y" +#line 265 "gram.y" { struct privilege *p = emalloc(sizeof(*p)); list2tq(&p->hostlist, yyvsp[-2].member); @@ -1081,53 +1120,61 @@ case 26: } break; case 27: -#line 269 "gram.y" +#line 275 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = FALSE; } break; case 28: -#line 273 "gram.y" +#line 279 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = TRUE; } break; case 29: -#line 279 "gram.y" +#line 285 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); } break; case 30: -#line 282 "gram.y" +#line 288 "gram.y" { yyval.member = new_member(NULL, ALL); } break; case 31: -#line 285 "gram.y" +#line 291 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); } break; case 32: -#line 288 "gram.y" +#line 294 "gram.y" { yyval.member = new_member(yyvsp[0].string, NTWKADDR); } break; case 33: -#line 291 "gram.y" +#line 297 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); } break; case 35: -#line 297 "gram.y" +#line 303 "gram.y" { list_append(yyvsp[-2].cmndspec, yyvsp[0].cmndspec); +#ifdef HAVE_SELINUX + /* propagate role and type */ + /* XXX - must be careful when freeing */ + if (yyvsp[0].cmndspec->role == NULL) + yyvsp[0].cmndspec->role = yyvsp[0].cmndspec->prev->role; + if (yyvsp[0].cmndspec->type == NULL) + yyvsp[0].cmndspec->type = yyvsp[0].cmndspec->prev->type; +#endif /* HAVE_SELINUX */ /* propagate tags and runas list */ if (yyvsp[0].cmndspec->tags.nopasswd == UNSPEC) yyvsp[0].cmndspec->tags.nopasswd = yyvsp[0].cmndspec->prev->tags.nopasswd; @@ -1147,17 +1194,21 @@ case 35: } break; case 36: -#line 318 "gram.y" +#line 332 "gram.y" { struct cmndspec *cs = emalloc(sizeof(*cs)); - if (yyvsp[-2].runas != NULL) { - list2tq(&cs->runasuserlist, yyvsp[-2].runas->runasusers); - list2tq(&cs->runasgrouplist, yyvsp[-2].runas->runasgroups); - efree(yyvsp[-2].runas); + if (yyvsp[-3].runas != NULL) { + list2tq(&cs->runasuserlist, yyvsp[-3].runas->runasusers); + list2tq(&cs->runasgrouplist, yyvsp[-3].runas->runasgroups); + efree(yyvsp[-3].runas); } else { tq_init(&cs->runasuserlist); tq_init(&cs->runasgrouplist); } +#ifdef HAVE_SELINUX + cs->role = yyvsp[-2].seinfo.role; + cs->type = yyvsp[-2].seinfo.type; +#endif cs->tags = yyvsp[-1].tag; cs->cmnd = yyvsp[0].member; cs->prev = cs; @@ -1170,111 +1221,158 @@ case 36: } break; case 37: -#line 340 "gram.y" +#line 358 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = FALSE; } break; case 38: -#line 344 "gram.y" +#line 362 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = TRUE; } break; case 39: -#line 350 "gram.y" +#line 368 "gram.y" { - yyval.runas = NULL; + yyval.string = yyvsp[0].string; } break; case 40: -#line 353 "gram.y" +#line 373 "gram.y" { - yyval.runas = yyvsp[-1].runas; + yyval.string = yyvsp[0].string; } break; case 41: -#line 358 "gram.y" +#line 378 "gram.y" +{ + yyval.seinfo.role = NULL; + yyval.seinfo.type = NULL; + } +break; +case 42: +#line 382 "gram.y" +{ + yyval.seinfo.role = yyvsp[0].string; + yyval.seinfo.type = NULL; + } +break; +case 43: +#line 386 "gram.y" +{ + yyval.seinfo.type = yyvsp[0].string; + yyval.seinfo.role = NULL; + } +break; +case 44: +#line 390 "gram.y" +{ + yyval.seinfo.role = yyvsp[-1].string; + yyval.seinfo.type = yyvsp[0].string; + } +break; +case 45: +#line 394 "gram.y" +{ + yyval.seinfo.type = yyvsp[-1].string; + yyval.seinfo.role = yyvsp[0].string; + } +break; +case 46: +#line 400 "gram.y" +{ + yyval.runas = NULL; + } +break; +case 47: +#line 403 "gram.y" +{ + yyval.runas = yyvsp[-1].runas; + } +break; +case 48: +#line 408 "gram.y" { yyval.runas = emalloc(sizeof(struct runascontainer)); yyval.runas->runasusers = yyvsp[0].member; yyval.runas->runasgroups = NULL; } break; -case 42: -#line 363 "gram.y" +case 49: +#line 413 "gram.y" { yyval.runas = emalloc(sizeof(struct runascontainer)); yyval.runas->runasusers = yyvsp[-2].member; yyval.runas->runasgroups = yyvsp[0].member; } break; -case 43: -#line 368 "gram.y" +case 50: +#line 418 "gram.y" { yyval.runas = emalloc(sizeof(struct runascontainer)); yyval.runas->runasusers = NULL; yyval.runas->runasgroups = yyvsp[0].member; } break; -case 44: -#line 375 "gram.y" +case 51: +#line 425 "gram.y" { yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv = UNSPEC; } break; -case 45: -#line 378 "gram.y" +case 52: +#line 428 "gram.y" { yyval.tag.nopasswd = TRUE; } break; -case 46: -#line 381 "gram.y" +case 53: +#line 431 "gram.y" { yyval.tag.nopasswd = FALSE; } break; -case 47: -#line 384 "gram.y" +case 54: +#line 434 "gram.y" { yyval.tag.noexec = TRUE; } break; -case 48: -#line 387 "gram.y" +case 55: +#line 437 "gram.y" { yyval.tag.noexec = FALSE; } break; -case 49: -#line 390 "gram.y" +case 56: +#line 440 "gram.y" { yyval.tag.setenv = TRUE; } break; -case 50: -#line 393 "gram.y" +case 57: +#line 443 "gram.y" { yyval.tag.setenv = FALSE; } break; -case 51: -#line 398 "gram.y" +case 58: +#line 448 "gram.y" { yyval.member = new_member(NULL, ALL); } break; -case 52: -#line 401 "gram.y" +case 59: +#line 451 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); } break; -case 53: -#line 404 "gram.y" +case 60: +#line 454 "gram.y" { struct sudo_command *c = emalloc(sizeof(*c)); c->cmnd = yyvsp[0].command.cmnd; @@ -1282,8 +1380,8 @@ case 53: yyval.member = new_member((char *)c, COMMAND); } break; -case 56: -#line 416 "gram.y" +case 63: +#line 466 "gram.y" { char *s; if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) { @@ -1292,15 +1390,15 @@ case 56: } } break; -case 58: -#line 426 "gram.y" +case 65: +#line 476 "gram.y" { list_append(yyvsp[-2].member, yyvsp[0].member); yyval.member = yyvsp[-2].member; } break; -case 61: -#line 436 "gram.y" +case 68: +#line 486 "gram.y" { char *s; if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) { @@ -1309,15 +1407,15 @@ case 61: } } break; -case 63: -#line 446 "gram.y" +case 70: +#line 496 "gram.y" { list_append(yyvsp[-2].member, yyvsp[0].member); yyval.member = yyvsp[-2].member; } break; -case 66: -#line 456 "gram.y" +case 73: +#line 506 "gram.y" { char *s; if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) { @@ -1326,8 +1424,8 @@ case 66: } } break; -case 69: -#line 469 "gram.y" +case 76: +#line 519 "gram.y" { char *s; if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) { @@ -1336,97 +1434,97 @@ case 69: } } break; -case 71: -#line 479 "gram.y" +case 78: +#line 529 "gram.y" { list_append(yyvsp[-2].member, yyvsp[0].member); yyval.member = yyvsp[-2].member; } break; -case 72: -#line 485 "gram.y" +case 79: +#line 535 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = FALSE; } break; -case 73: -#line 489 "gram.y" +case 80: +#line 539 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = TRUE; } break; -case 74: -#line 495 "gram.y" +case 81: +#line 545 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); } break; -case 75: -#line 498 "gram.y" +case 82: +#line 548 "gram.y" { yyval.member = new_member(NULL, ALL); } break; -case 76: -#line 501 "gram.y" +case 83: +#line 551 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); } break; -case 77: -#line 504 "gram.y" +case 84: +#line 554 "gram.y" { yyval.member = new_member(yyvsp[0].string, USERGROUP); } break; -case 78: -#line 507 "gram.y" +case 85: +#line 557 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); } break; -case 80: -#line 513 "gram.y" +case 87: +#line 563 "gram.y" { list_append(yyvsp[-2].member, yyvsp[0].member); yyval.member = yyvsp[-2].member; } break; -case 81: -#line 519 "gram.y" +case 88: +#line 569 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = FALSE; } break; -case 82: -#line 523 "gram.y" +case 89: +#line 573 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = TRUE; } break; -case 83: -#line 529 "gram.y" +case 90: +#line 579 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); } break; -case 84: -#line 532 "gram.y" +case 91: +#line 582 "gram.y" { yyval.member = new_member(NULL, ALL); } break; -case 85: -#line 535 "gram.y" +case 92: +#line 585 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); } break; -#line 1378 "y.tab.c" +#line 1476 "y.tab.c" } yyssp -= yym; yystate = *yyssp; diff --git a/gram.h b/gram.h index d4aaf6d5c..8f054916a 100644 --- a/gram.h +++ b/gram.h @@ -23,6 +23,8 @@ #define USERALIAS 279 #define RUNASALIAS 280 #define ERROR 281 +#define TYPE 282 +#define ROLE 283 #ifndef YYSTYPE_DEFINED #define YYSTYPE_DEFINED typedef union { @@ -33,6 +35,7 @@ typedef union { struct privilege *privilege; struct sudo_command command; struct cmndtag tag; + struct selinux_info seinfo; char *string; int tok; } YYSTYPE; diff --git a/gram.y b/gram.y index dd1c769e3..c2c68a778 100644 --- a/gram.y +++ b/gram.y @@ -122,6 +122,7 @@ yyerror(s) struct privilege *privilege; struct sudo_command command; struct cmndtag tag; + struct selinux_info seinfo; char *string; int tok; } @@ -154,6 +155,8 @@ yyerror(s) %token ':' '=' ',' '!' '+' '-' /* union member tokens */ %token '(' ')' /* runas tokens */ %token ERROR +%token TYPE /* SELinux type */ +%token ROLE /* SELinux role */ %type cmndspec %type cmndspeclist @@ -176,6 +179,9 @@ yyerror(s) %type privilege %type privileges %type cmndtag +%type selinux +%type rolespec +%type typespec %% @@ -296,6 +302,13 @@ host : ALIAS { cmndspeclist : cmndspec | cmndspeclist ',' cmndspec { list_append($1, $3); +#ifdef HAVE_SELINUX + /* propagate role and type */ + if ($3->role == NULL) + $3->role = $3->prev->role; + if ($3->type == NULL) + $3->type = $3->prev->type; +#endif /* HAVE_SELINUX */ /* propagate tags and runas list */ if ($3->tags.nopasswd == UNSPEC) $3->tags.nopasswd = $3->prev->tags.nopasswd; @@ -315,7 +328,7 @@ cmndspeclist : cmndspec } ; -cmndspec : runasspec cmndtag opcmnd { +cmndspec : runasspec selinux cmndtag opcmnd { struct cmndspec *cs = emalloc(sizeof(*cs)); if ($1 != NULL) { list2tq(&cs->runasuserlist, $1->runasusers); @@ -325,8 +338,12 @@ cmndspec : runasspec cmndtag opcmnd { tq_init(&cs->runasuserlist); tq_init(&cs->runasgrouplist); } - cs->tags = $2; - cs->cmnd = $3; +#ifdef HAVE_SELINUX + cs->role = $2.role; + cs->type = $2.type; +#endif + cs->tags = $3; + cs->cmnd = $4; cs->prev = cs; cs->next = NULL; /* sudo "ALL" implies the SETENV tag */ @@ -347,6 +364,38 @@ opcmnd : cmnd { } ; +rolespec : ROLE '=' WORD { + $$ = $3; + } + ; + +typespec : TYPE '=' WORD { + $$ = $3; + } + ; + +selinux : /* empty */ { + $$.role = NULL; + $$.type = NULL; + } + | rolespec { + $$.role = $1; + $$.type = NULL; + } + | typespec { + $$.type = $1; + $$.role = NULL; + } + | rolespec typespec { + $$.role = $1; + $$.type = $2; + } + | typespec rolespec { + $$.type = $1; + $$.role = $2; + } + ; + runasspec : /* empty */ { $$ = NULL; } @@ -638,12 +687,26 @@ init_parser(path, quiet) } while ((priv = tq_pop(&us->privileges)) != NULL) { struct member *runasuser = NULL, *runasgroup = NULL; +#ifdef HAVE_SELINUX + char *role = NULL, *type = NULL; +#endif /* HAVE_SELINUX */ while ((m = tq_pop(&priv->hostlist)) != NULL) { efree(m->name); efree(m); } while ((cs = tq_pop(&priv->cmndlist)) != NULL) { +#ifdef HAVE_SELINUX + /* Only free the first instance of a role/type. */ + if (cs->role != role) { + role = cs->role; + efree(cs->role); + } + if (cs->type != type) { + type = cs->type; + efree(cs->type); + } +#endif /* HAVE_SELINUX */ if (tq_last(&cs->runasuserlist) != runasuser) { runasuser = tq_last(&cs->runasuserlist); while ((m = tq_pop(&cs->runasuserlist)) != NULL) { diff --git a/ldap.c b/ldap.c index 490187172..418c02c14 100644 --- a/ldap.c +++ b/ldap.c @@ -1844,6 +1844,13 @@ sudo_ldap_lookup(nss, ret, pwflag) if (setenv_implied) def_setenv = TRUE; sudo_ldap_parse_options(ld, entry); +#ifdef HAVE_SELINUX + /* Set role and type if not specified on command line. */ + if (user_role == NULL) + user_role = def_role; + if (user_type == NULL) + user_type = def_type; +#endif /* HAVE_SELINUX */ /* make sure we don't reenter loop */ SET(ret, VALIDATE_OK); CLR(ret, VALIDATE_NOT_OK); diff --git a/parse.c b/parse.c index 2a0aaa468..4c3c12634 100644 --- a/parse.c +++ b/parse.c @@ -274,6 +274,13 @@ sudo_file_lookup(nss, validated, pwflag) if (cmnd_match != UNSPEC) { match = cmnd_match; tags = &cs->tags; +#ifdef HAVE_SELINUX + /* Set role and type if not specified on command line. */ + if (user_role == NULL) + user_role = cs->role ? estrdup(cs->role) : def_role; + if (user_type == NULL) + user_type = cs->type ? estrdup(cs->type) : def_type; +#endif /* HAVE_SELINUX */ goto matched2; } } @@ -311,6 +318,12 @@ sudo_file_append_cmnd(cs, tags, lbuf) { struct member *m; +#ifdef HAVE_SELINUX + if (cs->role) + lbuf_append(lbuf, "ROLE=", cs->role, " ", NULL); + if (cs->type) + lbuf_append(lbuf, "TYPE=", cs->type, " ", NULL); +#endif /* HAVE_SELINUX */ if (TAG_CHANGED(setenv)) { lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " : "NOSETENV: ", NULL); diff --git a/parse.h b/parse.h index 76395e8fe..5f6630053 100644 --- a/parse.h +++ b/parse.h @@ -48,6 +48,15 @@ struct cmndtag { char extra; }; +/* + * SELinux-specific container struct. + * Currently just contains a role and type. + */ +struct selinux_info { + char *role; + char *type; +}; + /* * The parses sudoers file is stored as a collection of linked lists, * modelled after the yacc grammar. @@ -100,6 +109,9 @@ struct cmndspec { struct member_list runasgrouplist; /* list of runas groups */ struct member *cmnd; /* command to allow/deny */ struct cmndtag tags; /* tag specificaion */ +#ifdef HAVE_SELINUX + char *role, *type; /* SELinux role and type */ +#endif }; /* diff --git a/pathnames.h.in b/pathnames.h.in index c8aebb9eb..b54877e22 100644 --- a/pathnames.h.in +++ b/pathnames.h.in @@ -108,6 +108,10 @@ #define _PATH_USRTMP "/usr/tmp/" #endif /* _PATH_USRTMP */ +#ifndef _PATH_SUDO_SESH +#undef _PATH_SUDO_SESH +#endif /* _PATH_SUDO_SESH */ + #ifndef _PATH_LDAP_CONF #undef _PATH_LDAP_CONF #endif /* _PATH_LDAP_CONF */ diff --git a/selinux.c b/selinux.c new file mode 100644 index 000000000..43df79bcd --- /dev/null +++ b/selinux.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2008 Dan Walsh + * + * Borrowed heavily from newrole source code + * Authors: + * Anthony Colatrella + * Tim Fraser + * Steve Grubb + * Darrel Goeddel + * Michael Thompson + * Dan Walsh + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WITH_AUDIT +#include +#endif + +#include /* for SECCLASS_CHR_FILE */ +#include /* for is_selinux_enabled() */ +#include /* for context-mangling functions */ +#include +#include + +#include "sudo.h" +#include "pathnames.h" + +/* + * This function attempts to revert the relabeling done to the tty. + * fd - referencing the opened ttyn + * ttyn - name of tty to restore + * tty_context - original context of the tty + * new_tty_context - context tty was relabeled to + * + * Returns zero on success, non-zero otherwise + */ +static int +restore_tty_label(int fd, const char *ttyn, security_context_t tty_context, + security_context_t new_tty_context) +{ + int rc = 0; + security_context_t chk_tty_context = NULL; + + if (!ttyn) + goto skip_relabel; + + if (!new_tty_context) + goto skip_relabel; + + /* Verify that the tty still has the context set by newrole. */ + if ((rc = fgetfilecon(fd, &chk_tty_context)) < 0) { + warning("unable to fgetfilecon %s", ttyn); + goto skip_relabel; + } + + if ((rc = strcmp(chk_tty_context, new_tty_context))) { + warningx("%s changed labels.", ttyn); + goto skip_relabel; + } + + if ((rc = fsetfilecon(fd, tty_context)) < 0) + warning("unable to restore context for %s", ttyn); + +skip_relabel: + freecon(chk_tty_context); + return(rc); +} + +/* + * This function attempts to relabel the tty. If this function fails, then + * the fd is closed, the contexts are free'd and -1 is returned. On success, + * a valid fd is returned and tty_context and new_tty_context are set. + * + * This function will not fail if it can not relabel the tty when selinux is + * in permissive mode. + */ +static int +relabel_tty(const char *ttyn, security_context_t new_context, + security_context_t * tty_context, security_context_t * new_tty_context) +{ + int fd; + int enforcing = security_getenforce(); + security_context_t tty_con = NULL; + security_context_t new_tty_con = NULL; + + if (!ttyn) + return(0); + + if (enforcing < 0) { + warningx("unable to determine enforcing mode."); + return(-1); + } + + /* Re-open TTY descriptor */ + fd = open(ttyn, O_RDWR | O_NONBLOCK); + if (fd == -1) { + warning("unable to open %s", ttyn); + return(-1); + } + (void)fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK); + + if (fgetfilecon(fd, &tty_con) < 0) { + warning("unable to get current context for %s, not relabeling tty", + ttyn); + if (enforcing) + goto error; + } + + if (tty_con && (security_compute_relabel(new_context, tty_con, + SECCLASS_CHR_FILE, &new_tty_con) < 0)) { + warning("unable to get new context for %s, not relabeling tty", ttyn); + if (enforcing) + goto error; + } + + if (new_tty_con != NULL) { + if (fsetfilecon(fd, new_tty_con) < 0) { + warning("unable to set new context for %s", ttyn); + if (enforcing) + goto error; + } + freecon(new_tty_con); + new_tty_con = NULL; + } + + *tty_context = tty_con; + *new_tty_context = new_tty_con; + return(fd); + +error: + freecon(tty_con); + close(fd); + return(-1); +} + +/* + * Returns a new security context based on the old context and the + * specified role and type. + */ +security_context_t +get_exec_context(security_context_t old_context, char *role, char *type) +{ + security_context_t new_context = NULL; + context_t context = NULL; + char *typebuf = NULL; + + /* We must have a role, the type is optional (we can use the default). */ + if (!role) { + warningx("you must specify a role."); + return(NULL); + } + if (!type) { + if (get_default_type(role, &typebuf)) { + warningx("unable to get default type"); + return(NULL); + } + type = typebuf; + } + + /* + * Expand old_context into a context_t so that we extract and modify + * its components easily. + */ + context = context_new(old_context); + + /* + * Replace the role and type in "context" with the role and + * type we will be running the command as. + */ + if (context_role_set(context, role)) { + warningx("failed to set new role %s", role); + goto error; + } + if (context_type_set(context, type)) { + warningx("failed to set new type %s", type); + goto error; + } + + /* + * Convert "context" back into a string and verify it. + */ + new_context = estrdup(context_str(context)); + if (security_check_context(new_context) < 0) { + warningx("%s is not a valid context", new_context); + goto error; + } + +#ifdef DEBUG + warningx("Your new context is %s", new_context); +#endif + + context_free(context); + return(new_context); + +error: + free(typebuf); + context_free(context); + freecon(new_context); + return(NULL); +} + +/* + * If the program is being run with a different security context we + * need to go through an intermediary process for the transition to + * be allowed by the policy. We use the "sesh" shell for this, which + * will simply execute the command pass to it on the command line. + */ +void +selinux_exec(char *role, char *type, char **argv, int login_shell) +{ + security_context_t old_context = NULL; + security_context_t new_context = NULL; + security_context_t tty_context = NULL; + security_context_t new_tty_context = NULL; + pid_t childPid; + int ttyfd; + + /* Must have a tty. */ + if (user_ttypath == NULL || *user_ttypath == '\0') + error(EXIT_FAILURE, "unable to determine tty"); + + /* Store the caller's SID in old_context. */ + if (getprevcon(&old_context)) + error(EXIT_FAILURE, "failed to get old_context"); + +#ifdef DEBUG + warningx("your old context was %s", old_context); +#endif + new_context = get_exec_context(old_context, role, type); + if (!new_context) + exit(EXIT_FAILURE); + + ttyfd = relabel_tty(user_ttypath, new_context, &tty_context, + &new_tty_context); + if (ttyfd < 0) + error(EXIT_FAILURE, "unable to setup tty context for %s", new_context); + +#ifdef DEBUG + warningx("your old tty context is %s", tty_context); + warningx("your new tty context is %s", new_tty_context); +#endif + + childPid = fork(); + if (childPid < 0) { + /* fork failed, no child to worry about */ + warning("unable to fork"); + if (restore_tty_label(ttyfd, user_ttypath, tty_context, new_tty_context)) + warningx("unable to restore tty label"); + exit(EXIT_FAILURE); + } else if (childPid) { + pid_t pid; + int status; + + /* Parent, wait for child to finish. */ + do { + pid = waitpid(childPid, &status, 0); + } while (pid == -1 && errno == EINTR); + + if (pid == -1) + error(EXIT_FAILURE, "waitpid"); + + if (restore_tty_label(ttyfd, user_ttypath, tty_context, new_tty_context)) + errorx(EXIT_FAILURE, "unable to restore tty label"); + + /* Preserve child exit status. */ + if (WIFEXITED(status)) + exit(WEXITSTATUS(status)); + exit(EXIT_FAILURE); + } + /* Child */ + /* Close the tty and reopen descriptors 0 through 2 */ + if (close(ttyfd) || close(STDIN_FILENO) || close(STDOUT_FILENO) || + close(STDERR_FILENO)) { + warning("could not close descriptors"); + goto error; + } + ttyfd = open(user_ttypath, O_RDONLY | O_NONBLOCK); + if (ttyfd != STDIN_FILENO) + goto error; + fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NONBLOCK); + ttyfd = open(user_ttypath, O_RDWR | O_NONBLOCK); + if (ttyfd != STDOUT_FILENO) + goto error; + fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NONBLOCK); + ttyfd = dup(STDOUT_FILENO); + if (ttyfd != STDERR_FILENO) + goto error; + + if (setexeccon(new_context)) { + warning("unable to set exec context to %s", new_context); + goto error; + } + +#ifdef WITH_AUDIT + if (send_audit_message(1, old_context, new_context, user_ttypath)) + goto error; +#endif + + /* We use the "spare" slot in argv to store sesh. */ + --argv; + argv[0] = login_shell ? "-sesh" : "sesh"; + argv[1] = safe_cmnd; + + execv(_PATH_SUDO_SESH, argv); + warning("%s", safe_cmnd); + +error: + _exit(EXIT_FAILURE); +}