[PATCH] secon: add support for setrans color information in prompt output

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds support for displaying SELinux context information in
colors defined by mcstrans(8)/secolor.conf(5).  The new behavior is
enabled through the use of the "-C/--color" option and requires the
"-P" option also be specified.

The reason for this addition is that in some situations, notably MLS,
users find it helpful to add SELinux context information to their prompt:

	# example taken from the RHEL6 CC certification bash scripts
	SEROLE=`secon -rP 2>/dev/null`
	SEMLS=`secon -lP 2>/dev/null`
	PS1="[\u/$SEROLE/$SEMLS@\h \W]\\$ "
	export PS1

With the added functionality provided by this patch we can also display
the associated color information (note the addition of the "C" option):

	SEROLE=`secon -rP 2>/dev/null`
	SEMLS=`secon -lPC 2>/dev/null`
	PS1="[\u/$SEROLE/$SEMLS@\h \W]\\$ "
	export PS1

Note that in the example above only the MLS range is colored, but the
patch does provide support for all of the color information provided
by mcstransd/secolor.conf (user,role,type,range).

Finally, one quick word on the colors themselves; the secolor.conf
configuration file allows 32-bit colors but the ANSI color coding only
allows 8-bit colors so the colors displayed by secon using the "-C"
option will be a bit lossy.

Signed-off-by: Paul Moore <pmoore@xxxxxxxxxx>
---
 policycoreutils/secon/secon.1 |    3 +
 policycoreutils/secon/secon.c |  207 ++++++++++++++++++++++++++++++++---------
 2 files changed, 167 insertions(+), 43 deletions(-)

diff --git a/policycoreutils/secon/secon.1 b/policycoreutils/secon/secon.1
index fcffbd8..6c30734 100644
--- a/policycoreutils/secon/secon.1
+++ b/policycoreutils/secon/secon.1
@@ -30,6 +30,9 @@ shows the usage information for secon
 \fB\-P\fR, \fB\-\-prompt\fR
 outputs data in a format suitable for a prompt
 .TP
+\fB\-C\fR, \fB\-\-color\fR
+outputs data with the associated ANSI color codes (requires -P)
+.TP
 \fB\-u\fR, \fB\-\-user\fR
 show the user of the security context
 .TP
diff --git a/policycoreutils/secon/secon.c b/policycoreutils/secon/secon.c
index 6ba47e9..ab4f7d0 100644
--- a/policycoreutils/secon/secon.c
+++ b/policycoreutils/secon/secon.c
@@ -19,8 +19,8 @@
 #define FALSE 0
 
 #define SECON_CONF_PROG_NAME "secon"	/* default program name */
-#define SECON_OPTS_SM "hVurtscmPRfLp"	/* small options available, print */
-#define SECON_OPTS_GO "hVurtlscmPRf:L:p:"	/* small options available, getopt */
+#define SECON_OPTS_SM "hVurtscmPRCfLp"	/* small options available, print */
+#define SECON_OPTS_GO "hVurtlscmPRCf:L:p:"	/* small options available, getopt */
 
 #define OPTS_FROM_ARG      0
 #define OPTS_FROM_FILE     1
@@ -35,6 +35,19 @@
 #define OPTS_FROM_PROCFS   10
 #define OPTS_FROM_PROCKEY  11
 
+struct context_color_t {
+	unsigned int valid;
+
+	char *user_fg;
+	char *user_bg;
+	char *role_fg;
+	char *role_bg;
+	char *type_fg;
+	char *type_bg;
+	char *range_fg;
+	char *range_bg;
+};
+
 struct {
 	unsigned int disp_user:1;
 	unsigned int disp_role:1;
@@ -44,6 +57,7 @@ struct {
 	unsigned int disp_mlsr:1;
 
 	unsigned int disp_raw:1;
+	unsigned int disp_color:1;
 
 	unsigned int disp_prompt:1;	/* no return, use : to sep */
 
@@ -57,8 +71,7 @@ struct {
 	} f;
 } opts[1] = { {
 		FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
-		    FALSE, FALSE, OPTS_FROM_ARG, {
-0}}};
+		    FALSE, FALSE, FALSE, OPTS_FROM_ARG, {0} } };
 
 static void usage(const char *name, int exit_code)
 {
@@ -75,6 +88,7 @@ static void usage(const char *name, int exit_code)
 		"          --mls-range   -m     Show the sensitivity to clearance range of \n"
 		"                               the context.\n"
 		"          --raw         -R     Show the context in \"raw\" format.\n"
+		"          --color       -C     Output using ANSI color codes (requires -P).\n"
 		"          --current            Get the context for the current process.\n"
 		"          --self               Get the context for the current process.\n"
 		"          --self-exec          Get the exec context for the current process.\n"
@@ -156,6 +170,7 @@ static void cmd_line(int argc, char *argv[])
 		{"mls-range", no_argument, NULL, 'm'},
 
 		{"raw", no_argument, NULL, 'R'},
+		{"color", no_argument, NULL, 'C'},
 
 		{"current", no_argument, NULL, 1},
 		{"self", no_argument, NULL, 1},
@@ -232,6 +247,9 @@ static void cmd_line(int argc, char *argv[])
 		case 'R':
 			opts->disp_raw = !opts->disp_raw;
 			break;
+		case 'C':
+			opts->disp_color = !opts->disp_color;
+			break;
 		case 1:
 			opts->from_type = OPTS_FROM_CUR;
 			break;
@@ -370,16 +388,18 @@ static int my_getpidkeycreatecon_raw(pid_t pid, security_context_t * con)
 static security_context_t get_scon(void)
 {
 	static char dummy_NIL[1] = "";
-	security_context_t con = NULL;
+	security_context_t con = NULL, con_tmp;
 	int ret = -1;
-	int raw = TRUE;
 
 	switch (opts->from_type) {
 	case OPTS_FROM_ARG:
-		if (!(con = strdup(opts->f.arg)))
+		if (!(con_tmp = strdup(opts->f.arg)))
 			err(EXIT_FAILURE,
 			    " Couldn't allocate security context");
-		raw = !opts->disp_raw;	/* always do conversion */
+		if (selinux_trans_to_raw_context(con_tmp, &con) < 0)
+			err(EXIT_FAILURE,
+			    " Couldn't translate security context");
+		freecon(con_tmp);
 		break;
 
 	case OPTS_FROM_STDIN:
@@ -396,11 +416,13 @@ static security_context_t get_scon(void)
 				ptr[strcspn(ptr, " \n\t")] = 0;
 			}
 
-			if (!(con = strdup(ptr)))
+			if (!(con_tmp = strdup(ptr)))
 				err(EXIT_FAILURE,
 				    " Couldn't allocate security context");
-
-			raw = !opts->disp_raw;	/* always do conversion */
+			if (selinux_trans_to_raw_context(con_tmp, &con) < 0)
+				err(EXIT_FAILURE,
+				    " Couldn't translate security context");
+			freecon(con_tmp);
 			break;
 		}
 
@@ -511,26 +533,69 @@ static security_context_t get_scon(void)
 		assert(FALSE);
 	}
 
-	if (opts->disp_raw != raw) {
-		security_context_t ncon = NULL;
+	return (con);
+}
 
-		if (opts->disp_raw)
-			selinux_trans_to_raw_context(con, &ncon);
-		else
-			selinux_raw_to_trans_context(con, &ncon);
+static unsigned int disp__color_to_ansi(const char *color_str)
+{
+	int val = 30;
 
-		freecon(con);
-		con = ncon;
-	}
+	/* NOTE: ansi black is 30 for foreground colors */
 
-	return (con);
+	/* red */
+	if (strncasecmp(&color_str[1], "7f", 2) >= 0)
+		val += 1;
+	/* green */
+	if (strncasecmp(&color_str[3], "7f", 2) >= 0)
+		val += 2;
+	/* blue */
+	if (strncasecmp(&color_str[5], "7f", 2) >= 0)
+		val += 4;
+
+	return val;
 }
 
-static void disp__con_val(const char *name, const char *val)
+static char *disp__con_color_ansi(const char *name,
+				  struct context_color_t *color)
+{
+	unsigned int fg, bg;
+	char *ansi;
+	int ansi_len = strlen("\e[99;99m") + 1;
+
+	/* NOTE: ansi background codes are the same as foreground codes +10 */
+
+	if (xstreq("user", name)) {
+		fg = disp__color_to_ansi(color->user_fg);
+		bg = disp__color_to_ansi(color->user_bg) + 10;
+	} else if (xstreq("role", name)) {
+		fg = disp__color_to_ansi(color->role_fg);
+		bg = disp__color_to_ansi(color->role_bg) + 10;
+	} else if (xstreq("type", name)) {
+		fg = disp__color_to_ansi(color->type_fg);
+		bg = disp__color_to_ansi(color->type_bg) + 10;
+	} else if (xstreq("sensitivity", name) ||
+		   xstreq("clearance", name) ||
+		   xstreq("mls-range", name)) {
+		fg = disp__color_to_ansi(color->range_fg);
+		bg = disp__color_to_ansi(color->range_bg) + 10;
+	} else
+		err(EXIT_FAILURE, " No color information for context field");
+
+	if (!(ansi = malloc(ansi_len)))
+		err(EXIT_FAILURE, " Unable to allocate memory");
+	if (snprintf(ansi, ansi_len, "\e[%d;%dm", fg, bg) > ansi_len)
+		err(EXIT_FAILURE, " Unable to convert colors to ANSI codes");
+
+	return ansi;
+}
+
+static void disp__con_val(const char *name, const char *val,
+			  struct context_color_t *color)
 {
 	static int done = FALSE;
 
 	assert(name);
+	assert(color);
 
 	if (!val)
 		val = "";	/* targeted has no "level" etc.,
@@ -540,7 +605,14 @@ static void disp__con_val(const char *name, const char *val)
 		if (xstreq("mls-range", name) && !*val)
 			return;	/* skip, mls-range if it's empty */
 
+		if (opts->disp_color && color->valid) {
+			char *ansi = disp__con_color_ansi(name, color);
+			fprintf(stdout, "%s", ansi);
+			free(ansi);
+		}
 		fprintf(stdout, "%s%s", done ? ":" : "", val);
+		if (opts->disp_color && color->valid)
+			fprintf(stdout, "\e[0m");
 	} else if (disp_multi())
 		fprintf(stdout, "%s: %s\n", name, val);
 	else
@@ -549,35 +621,81 @@ static void disp__con_val(const char *name, const char *val)
 	done = TRUE;
 }
 
-static void disp_con(security_context_t scon)
+static void disp_con(security_context_t scon_raw)
 {
+	security_context_t scon_trans, scon;
 	context_t con = NULL;
+	char *color_str = NULL;
+	struct context_color_t color = { .valid = 0 };
+
+	selinux_raw_to_trans_context(scon_raw, &scon_trans);
+	if (opts->disp_raw)
+		scon = scon_raw;
+	else
+		scon = scon_trans;
 
 	if (!*scon) {		/* --self-exec and --self-fs etc. */
 		if (opts->disp_user)
-			disp__con_val("user", NULL);
+			disp__con_val("user", NULL, &color);
 		if (opts->disp_role)
-			disp__con_val("role", NULL);
+			disp__con_val("role", NULL, &color);
 		if (opts->disp_type)
-			disp__con_val("type", NULL);
+			disp__con_val("type", NULL, &color);
 		if (opts->disp_sen)
-			disp__con_val("sensitivity", NULL);
+			disp__con_val("sensitivity", NULL, &color);
 		if (opts->disp_clr)
-			disp__con_val("clearance", NULL);
+			disp__con_val("clearance", NULL, &color);
 		if (opts->disp_mlsr)
-			disp__con_val("mls-range", NULL);
+			disp__con_val("mls-range", NULL, &color);
 		return;
 	}
 
+	if (opts->disp_color) {
+		if (selinux_raw_context_to_color(scon_raw, &color_str) < 0)
+			errx(EXIT_FAILURE, "Couldn't determine colors for: %s",
+			     scon);
+
+		color.user_fg = strtok(color_str, " ");
+		if (!color.user_fg)
+			errx(EXIT_FAILURE, "Invalid color string");
+		color.user_bg = strtok(NULL, " ");
+		if (!color.user_bg)
+			errx(EXIT_FAILURE, "Invalid color string");
+
+		color.role_fg = strtok(NULL, " ");
+		if (!color.role_fg)
+			errx(EXIT_FAILURE, "Invalid color string");
+		color.role_bg = strtok(NULL, " ");
+		if (!color.role_bg)
+			errx(EXIT_FAILURE, "Invalid color string");
+
+		color.type_fg = strtok(NULL, " ");
+		if (!color.type_fg)
+			errx(EXIT_FAILURE, "Invalid color string");
+		color.type_bg = strtok(NULL, " ");
+		if (!color.type_bg)
+			errx(EXIT_FAILURE, "Invalid color string");
+
+		color.range_fg = strtok(NULL, " ");
+		if (!color.range_fg)
+			errx(EXIT_FAILURE, "Invalid color string");
+		color.range_bg = strtok(NULL, " ");
+
+		color.valid = 1;
+	};
+
 	if (!(con = context_new(scon)))
 		errx(EXIT_FAILURE, "Couldn't create context from: %s", scon);
 
-	if (opts->disp_user)
-		disp__con_val("user", context_user_get(con));
-	if (opts->disp_role)
-		disp__con_val("role", context_role_get(con));
-	if (opts->disp_type)
-		disp__con_val("type", context_type_get(con));
+	if (opts->disp_user) {
+		disp__con_val("user", context_user_get(con), &color);
+	}
+	if (opts->disp_role) {
+		disp__con_val("role", context_role_get(con), &color);
+	}
+	if (opts->disp_type) {
+		disp__con_val("type", context_type_get(con), &color);
+	}
 	if (opts->disp_sen) {
 		const char *val = NULL;
 		char *tmp = NULL;
@@ -594,7 +712,7 @@ static void disp_con(security_context_t scon)
 		if (strchr(tmp, '-'))
 			*strchr(tmp, '-') = 0;
 
-		disp__con_val("sensitivity", tmp);
+		disp__con_val("sensitivity", tmp, &color);
 
 		free(tmp);
 	}
@@ -612,30 +730,33 @@ static void disp_con(security_context_t scon)
 			errx(EXIT_FAILURE, "Couldn't create context from: %s",
 			     scon);
 		if (strchr(tmp, '-'))
-			disp__con_val("clearance", strchr(tmp, '-') + 1);
+			disp__con_val("clearance", strchr(tmp, '-') + 1, &color);
 		else
-			disp__con_val("clearance", tmp);
+			disp__con_val("clearance", tmp, &color);
 
 		free(tmp);
 	}
 
 	if (opts->disp_mlsr)
-		disp__con_val("mls-range", context_range_get(con));
+		disp__con_val("mls-range", context_range_get(con), &color);
 
 	context_free(con);
+	freecon(scon_trans);
+	if (color_str)
+		free(color_str);
 }
 
 int main(int argc, char *argv[])
 {
-	security_context_t scon = NULL;
+	security_context_t scon_raw = NULL;
 
 	cmd_line(argc, argv);
 
-	scon = get_scon();
+	scon_raw = get_scon();
 
-	disp_con(scon);
+	disp_con(scon_raw);
 
-	freecon(scon);
+	freecon(scon_raw);
 
 	exit(EXIT_SUCCESS);
 }


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with
the words "unsubscribe selinux" without quotes as the message.


[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux