Subject: [PATCH] net-tools: netstat add SELinux support.
From: Xin Ouyang <[email-masked]>
Date: Wed, 13 Jun 2012 13:32:01 +0800

Upstream-Status: Inappropriate [configuration]

Signed-off-by: Xin Ouyang <[email-masked]>
Signed-off-by: Adrian Dudau <[email-masked]>
---
 Makefile  |  9 ++++++++-
 netstat.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile
index 8fcc55c..0b5c395 100644
--- a/Makefile
+++ b/Makefile
@@ -116,6 +116,13 @@ NET_LIB = $(NET_LIB_PATH)/lib$(NET_LIB_NAME).a
 CFLAGS	= $(COPTS) -I. -idirafter ./include/ -I$(NET_LIB_PATH)
 LDFLAGS	= $(LOPTS) -L$(NET_LIB_PATH)
 
+ifeq ($(HAVE_SELINUX),1)
+SELINUX_LDFLAGS	= -lselinux
+CFLAGS		+= -DHAVE_SELINUX
+else
+SELINUX_LDFLAGS	=
+endif
+
 SUBDIRS	= man/ $(NET_LIB_PATH)/
 
 ifeq ($(origin CC), undefined)
@@ -209,7 +216,7 @@ plipconfig:	$(NET_LIB) plipconfig.o
 		$(CC) $(LDFLAGS) -o plipconfig plipconfig.o $(NLIB)
 
 netstat:	$(NET_LIB) netstat.o statistics.o
-		$(CC) $(LDFLAGS) -o netstat netstat.o statistics.o $(NLIB) $(RESLIB)
+		$(CC) $(SELINUX_LDFLAGS) $(LDFLAGS) -o netstat netstat.o statistics.o $(NLIB) $(RESLIB)
 
 iptunnel:	$(NET_LIB) iptunnel.o
 		$(CC) $(LDFLAGS) -o iptunnel iptunnel.o $(NLIB) $(RESLIB)
diff --git a/netstat.c b/netstat.c
index fc10414..a773e81 100644
--- a/netstat.c
+++ b/netstat.c
@@ -90,6 +90,12 @@
 #include <sys/types.h>
 #include <asm-generic/param.h>
 
+#if HAVE_SELINUX
+#include <selinux/selinux.h>
+#else
+#define security_context_t char*
+#endif
+
 #include "net-support.h"
 #include "pathnames.h"
 #include "version.h"
@@ -101,6 +107,7 @@
 #include "proc.h"
 
 #define PROGNAME_WIDTH 20
+#define SELINUX_WIDTH 50
 
 #if !defined(s6_addr32) && defined(in6a_words)
 #define s6_addr32 in6a_words	/* libinet6			*/
@@ -180,6 +187,7 @@ int flag_wide= 0;
 int flag_prg = 0;
 int flag_arg = 0;
 int flag_ver = 0;
+int flag_selinux = 0;
 
 FILE *procinfo;
 
@@ -243,12 +251,17 @@ FILE *procinfo;
 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
 #define PROGNAME_WIDTH2(s) #s
 
+#define SELINUX_WIDTHs SELINUX_WIDTH1(SELINUX_WIDTH)
+#define SELINUX_WIDTH1(s) SELINUX_WIDTH2(s)
+#define SELINUX_WIDTH2(s) #s
+
 #define PRG_HASH_SIZE 211
 
 static struct prg_node {
     struct prg_node *next;
     unsigned long inode;
     char name[PROGNAME_WIDTH];
+    char scon[SELINUX_WIDTH];
 } *prg_hash[PRG_HASH_SIZE];
 
 static char prg_cache_loaded = 0;
@@ -256,9 +269,12 @@ static char prg_cache_loaded = 0;
 #define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
 
 #define PROGNAME_BANNER "PID/Program name"
+#define SELINUX_BANNER "Security Context"
 
 #define print_progname_banner() do { if (flag_prg) printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER); } while (0)
 
+#define print_selinux_banner() do { if (flag_selinux) printf("%-" SELINUX_WIDTHs "s"," " SELINUX_BANNER); } while (0)
+
 #define PRG_LOCAL_ADDRESS "local_address"
 #define PRG_INODE	 "inode"
 #define PRG_SOCKET_PFX    "socket:["
@@ -280,7 +296,7 @@ static char prg_cache_loaded = 0;
 /* NOT working as of glibc-2.0.7: */
 #undef  DIRENT_HAVE_D_TYPE_WORKS
 
-static void prg_cache_add(unsigned long inode, char *name)
+static void prg_cache_add(unsigned long inode, char *name, char *scon)
 {
     unsigned hi = PRG_HASHIT(inode);
     struct prg_node **pnp,*pn;
@@ -301,6 +317,14 @@ static void prg_cache_add(unsigned long inode, char *name)
     if (strlen(name)>sizeof(pn->name)-1) 
 	name[sizeof(pn->name)-1]='\0';
     strcpy(pn->name,name);
+
+    {
+	int len=(strlen(scon)-sizeof(pn->scon))+1;
+	if (len > 0)
+	    strcpy(pn->scon,&scon[len+1]);
+	else
+	    strcpy(pn->scon,scon);
+    }
 }
 
 static const char *prg_cache_get(unsigned long inode)
@@ -313,6 +337,16 @@ static const char *prg_cache_get(unsigned long inode)
     return("-");
 }
 
+static const char *prg_cache_get_con(unsigned long inode)
+{
+    unsigned hi=PRG_HASHIT(inode);
+    struct prg_node *pn;
+
+    for (pn=prg_hash[hi];pn;pn=pn->next)
+        if (pn->inode==inode) return(pn->scon);
+    return("-");
+}
+
 static void prg_cache_clear(void)
 {
     struct prg_node **pnp,*pn;
@@ -384,6 +418,7 @@ static void prg_cache_load(void)
     const char *cs,*cmdlp;
     DIR *dirproc=NULL,*dirfd=NULL;
     struct dirent *direproc,*direfd;
+    security_context_t scon=NULL;
 
     if (prg_cache_loaded || !flag_prg) return;
     prg_cache_loaded=1;
@@ -453,7 +488,15 @@ static void prg_cache_load(void)
 	    }
 
 	    snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
-	    prg_cache_add(inode, finbuf);
+#if HAVE_SELINUX
+	    if (getpidcon(atoi(direproc->d_name), &scon) == -1) {
+		scon=strdup("-");
+	    }
+	    prg_cache_add(inode, finbuf, scon);
+	    freecon(scon);
+#else
+	    prg_cache_add(inode, finbuf, "-");
+#endif
 	}
 	closedir(dirfd); 
 	dirfd = NULL;
@@ -573,6 +616,8 @@ static void finish_this_one(int uid, unsigned long inode, const char *timers)
     }
     if (flag_prg)
 	printf(" %-16s",prg_cache_get(inode));
+    if (flag_selinux)
+	printf("%-" SELINUX_WIDTHs "s",prg_cache_get_con(inode));
     if (flag_opt)
 	printf(" %s", timers);
     putchar('\n');
@@ -1566,6 +1611,8 @@ static void unix_do_one(int nr, const char *line)
 	printf("-        ");
     if (flag_prg)
 	printf("%-" PROGNAME_WIDTHs "s",(has & HAS_INODE?prg_cache_get(inode):"-"));
+    if (flag_selinux)
+	printf("%-" SELINUX_WIDTHs "s",(has & HAS_INODE?prg_cache_get_con(inode):"-"));
     puts(path);
 }
 
@@ -1584,6 +1631,7 @@ static int unix_info(void)
 
     printf(_("\nProto RefCnt Flags       Type       State         I-Node  "));
     print_progname_banner();
+    print_selinux_banner();
     printf(_(" Path\n"));	/* xxx */
 
     {
@@ -1874,6 +1922,7 @@ static void usage(void)
     fprintf(stderr, _("        -o, --timers             display timers\n"));
     fprintf(stderr, _("        -F, --fib                display Forwarding Information Base (default)\n"));
     fprintf(stderr, _("        -C, --cache              display routing cache instead of FIB\n\n"));
+    fprintf(stderr, _("        -Z, --context            display SELinux security context for sockets\n\n"));
 
     fprintf(stderr, _("  <Socket>={-t|--tcp} {-u|--udp} {-S|--sctp} {-w|--raw} {-x|--unix} --ax25 --ipx --netrom\n"));
     fprintf(stderr, _("  <AF>=Use '-6|-4' or '-A <af>' or '--<af>'; default: %s\n"), DFLT_AF);
@@ -1920,6 +1969,7 @@ int main
 	{"cache", 0, 0, 'C'},
 	{"fib", 0, 0, 'F'},
 	{"groups", 0, 0, 'g'},
+	{"context", 0, 0, 'Z'},
 	{NULL, 0, 0, 0}
     };
 
@@ -1931,7 +1981,7 @@ int main
     getroute_init();		/* Set up AF routing support */
 
     afname[0] = '\0';
-    while ((i = getopt_long(argc, argv, "MCFA:acdegphinNorstuSWVv?wxl64", longopts, &lop)) != EOF)
+    while ((i = getopt_long(argc, argv, "MCFA:acdegphinNorstuSWVv?wxlZ64", longopts, &lop)) != EOF)
 	switch (i) {
 	case -1:
 	    break;
@@ -2036,6 +2086,19 @@ int main
 	    if (aftrans_opt("unix"))
 		exit(1);
 	    break;
+	case 'Z':
+#if HAVE_SELINUX
+	    if (is_selinux_enabled() <= 0) {
+		fprintf(stderr, _("SELinux is not enabled on this machine.\n"));
+		exit(1);
+	    }
+	    flag_prg++;
+	    flag_selinux++;
+#else
+	    fprintf(stderr, _("SELinux is not enabled for this application.\n"));
+	    exit(1);
+#endif
+	    break;
 	case '?':
 	case 'h':
 	    usage();
-- 
1.9.1