[redhat-lspp] [PATCH] setrans - selinux translation daemon

Chad Hanson chanson at trustedcs.com
Wed Apr 26 21:12:07 UTC 2006


I am attaching the following patches as an initial framework for the SELinux
translation daemon.

The patches include functionality in the following areas:  daemon, client,
initialization, and initial policy.

After implementing, we should change the file contexts of the translation
configuration files to SystemHigh. A label arbitration routine needs to be
added into the daemon to determine whether caller should be able translate
the requested labels.

-Chad
-------------- next part --------------
diff -Nur libsetrans-0.1.20.orig/include/setrans.h libsetrans-0.1.20/include/setrans.h
--- libsetrans-0.1.20.orig/include/setrans.h	1970-01-01 00:00:00.000000000 +0000
+++ libsetrans-0.1.20/include/setrans.h	2006-04-25 19:07:08.000000000 +0000
@@ -0,0 +1,26 @@
+/* Copyright (c) 2006 Trusted Computer Solutions, Inc. */
+
+#ifndef _SETRANS_H
+#define _SETRANS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This must be called once, prior to calling any other 
+   translation function.
+   Returns nonzero if translations cannot be performed, 
+   or 0 otherwise. */
+int init_context_translations(void);
+
+/* Perform context translation.
+   Caller must free the resulting context.
+   Returns nonzero if error or 0 otherwise. */
+int translate_context(const char *, char **);
+int untranslate_context(const char *, char **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SETRANS_H */
diff -Nur libsetrans-0.1.20.orig/src/Makefile libsetrans-0.1.20/src/Makefile
--- libsetrans-0.1.20.orig/src/Makefile	2005-09-27 16:21:13.000000000 +0000
+++ libsetrans-0.1.20/src/Makefile	2006-04-25 19:07:08.000000000 +0000
@@ -2,6 +2,7 @@
 PREFIX ?= $(DESTDIR)/usr
 LIBDIR ?= $(PREFIX)/lib
 SHLIBDIR ?= $(DESTDIR)/lib
+SBINDIR ?= $(DESTDIR)/sbin
 
 LIBVERSION = 0
 
@@ -9,13 +10,17 @@
 LIBA=libsetrans.a 
 TARGET=libsetrans.so
 LIBSO=$(TARGET).$(LIBVERSION)
-OBJS= $(patsubst %.c,%.o,$(wildcard *.c))
-LOBJS= $(patsubst %.c,%.lo,$(wildcard *.c))
+LIBRARY_SRC=setrans_client.c
+OBJS= $(patsubst %.c,%.o,$(LIBRARY_SRC))
+LOBJS= $(patsubst %.c,%.lo,$(LIBRARY_SRC))
+PROG_SRC=setrans.c setransd.c
+PROG_OBJS= $(patsubst %.c,%.o,$(PROG_SRC))
+PROG=setransd
 CFLAGS ?= -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute
 override CFLAGS += -I../include -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
 RANLIB=ranlib
 
-all: $(LIBA) $(LIBSO)
+all: $(LIBA) $(LIBSO) $(PROG)
 
 $(LIBA):  $(OBJS)
 	$(AR) rcs $@ $^
@@ -25,6 +30,9 @@
 	$(CC) $(LDFLAGS) -shared -o $@ $^ -ldl -Wl,-soname,$(LIBSO),-z,defs -lselinux
 	ln -sf $@ $(TARGET) 
 
+$(PROG): $(PROG_OBJS)
+	$(CC) $(LDFLAGS) -o $@ $^ -lselinux -lpthread -L. -lsetrans
+
 %.o:  %.c 
 	$(CC) $(CFLAGS) -c -o $@ $<
 
@@ -37,10 +45,12 @@
 	test -d $(SHLIBDIR) || install -m 755 -d $(SHLIBDIR)
 	install -m 755 $(LIBSO) $(SHLIBDIR)
 	cd $(LIBDIR) && ln -sf ../../`basename $(SHLIBDIR)`/$(LIBSO) $(TARGET)
+	test -d $(SBINDIR) || install -m 755 -d $(SBINDIR)
+	install -m 755 $(PROG) $(SBINDIR)
 
 relabel:
 	/sbin/restorecon $(SHLIBDIR)/$(LIBSO)
 
 clean: 
-	-rm -f $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET) *~ \#*
+	-rm -f $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET) $(PROG) $(PROG_OBJS) *~ \#*
 
diff -Nur libsetrans-0.1.20.orig/src/setrans.c libsetrans-0.1.20/src/setrans.c
--- libsetrans-0.1.20.orig/src/setrans.c	2006-03-13 18:58:23.000000000 +0000
+++ libsetrans-0.1.20/src/setrans.c	2006-04-25 19:07:08.000000000 +0000
@@ -376,7 +376,7 @@
    Might want to change to some kind of reload eventually, for long running
    processes.
  */
-int init_context_translations(void) {
+int init_translations(void) {
 	FILE *cfg=NULL;
 	labels_t *ptr=NULL;
 	labels_t *next=NULL;
@@ -415,7 +415,7 @@
 }
 
 /* Look for selabel via external name */
-int translate_context( const security_context_t oldcon, security_context_t *rcon) {
+int trans_context( const security_context_t oldcon, security_context_t *rcon) {
 	const char *range=NULL;
 	context_t con=context_new(oldcon);
 
@@ -435,7 +435,7 @@
 }
 
 /* Look for selabel via external name */
-int untranslate_context( const security_context_t oldcon, security_context_t *rcon) {
+int untrans_context( const security_context_t oldcon, security_context_t *rcon) {
 	const char *range=NULL;
 	const char *newrange=NULL;
 	context_t con=context_new(oldcon);
@@ -447,9 +447,7 @@
 			const char *ptr=strchr(range,'-');
 			/* if ranged label */
 			if(ptr) {
-                                /* Now tmpbuf has minimum level string
-				 * and &range[i] has clearance level string.
-				 * If minimum and clearance level is same 
+				/* If minimum and clearance level is same 
 				 * use single level string as range.
 				 * This removes the need to define same 
 				 * level ranges (ex: SystemHigh-SystemHigh)
diff -Nur libsetrans-0.1.20.orig/src/setrans_client.c libsetrans-0.1.20/src/setrans_client.c
--- libsetrans-0.1.20.orig/src/setrans_client.c	1970-01-01 00:00:00.000000000 +0000
+++ libsetrans-0.1.20/src/setrans_client.c	2006-04-25 19:08:40.000000000 +0000
@@ -0,0 +1,222 @@
+/* Copyright (c) 2006 Trusted Computer Solutions, Inc. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <selinux/selinux.h>
+#include "dso.h"
+#include "setrans_internal.h"
+#include "setrans.h"
+
+
+/*
+ * setransd_open
+ *
+ * This function opens a socket to the setransd.
+ * Returns:  on success, a file descriptor ( >= 0 ) to the socket
+ *           on error, a negative value
+ */
+static int
+setransd_open(void)
+{
+	struct sockaddr_un addr;
+	int fd;
+
+	fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0)	{
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strcpy(addr.sun_path, SETRANS_UNIX_SOCKET);
+	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+/* Returns: 0 on success, <0 on failure */
+static int
+send_request(int fd, uint32_t function, const char *data1, const char *data2)
+{
+	struct iovec req_hdr[4];
+	uint32_t data1_size;
+	uint32_t data2_size;
+	struct iovec req_data[2];
+	ssize_t count;
+
+	if (fd < 0)
+		return -1;
+
+	if (!data1)
+		data1 = "";
+	if (!data2)
+		data2 = "";
+
+	data1_size = strlen(data1) + 1;
+	data2_size = strlen(data2) + 1;
+
+	req_hdr[0].iov_base = &function;
+	req_hdr[0].iov_len = sizeof(function);
+	req_hdr[1].iov_base = &data1_size;
+	req_hdr[1].iov_len = sizeof(data1_size);
+	req_hdr[2].iov_base = &data2_size;
+	req_hdr[2].iov_len = sizeof(data2_size);
+
+	while (((count = writev(fd, req_hdr, 3)) < 0) && (errno == EINTR));
+	if (count != (sizeof(function) + sizeof(data1_size) +
+	              sizeof(data2_size) )) {
+		return -1;
+	}
+
+	req_data[0].iov_base = (char *)data1;
+	req_data[0].iov_len = data1_size;
+	req_data[1].iov_base = (char *)data2;
+	req_data[1].iov_len = data2_size;
+
+	while (((count = writev(fd, req_data, 2)) < 0) && (errno == EINTR));
+	if (count < 0 || (uint32_t)count != (data1_size + data2_size)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Returns: 0 on success, <0 on failure */
+static int
+receive_response(int fd, uint32_t function, char **outdata, int32_t *ret_val)
+{
+	struct iovec resp_hdr[3];
+	uint32_t func;
+	uint32_t data_size;
+	char *data;
+	struct iovec resp_data;
+	ssize_t count;
+
+	if (fd < 0)
+		return -1;
+
+	resp_hdr[0].iov_base = &func;
+	resp_hdr[0].iov_len = sizeof(func);
+	resp_hdr[1].iov_base = &data_size;
+	resp_hdr[1].iov_len = sizeof(data_size);
+	resp_hdr[2].iov_base = ret_val;
+	resp_hdr[2].iov_len = sizeof(*ret_val);
+
+	while (((count = readv(fd, resp_hdr, 3)) < 0) && (errno == EINTR));
+	if (count != (sizeof(func) + sizeof(data_size) + sizeof(*ret_val))) {
+		return -1;
+	}
+
+	if (func != function || !data_size) {
+		return -1;
+	}
+
+	data = malloc(data_size);
+	if (!data) {
+		return -1; 
+	}
+
+	resp_data.iov_base = data;
+	resp_data.iov_len = data_size;
+
+	while (((count = readv(fd, &resp_data, 1))) < 0 && (errno == EINTR));
+	if (count < 0 || (uint32_t)count != data_size || data[data_size - 1] != '\0') {
+		free(data);
+		return -1;
+	}
+
+	*outdata = data;
+	return 0;
+}
+
+int
+translate_context(const char *in, char **out)
+{
+	int ret;
+	int32_t ret_val;
+	int fd;
+
+	*out = NULL;
+
+	fd = setransd_open();
+	if (fd < 0)
+                return fd;
+
+	ret = send_request(fd, RAW_TO_TRANS_CONTEXT, in, NULL);
+	if (ret)
+		goto out;
+
+	ret = receive_response(fd, RAW_TO_TRANS_CONTEXT, out, &ret_val);
+	if (ret)
+		goto out;
+
+	ret = ret_val;
+out:
+	close(fd);
+	return ret;
+}
+
+int
+untranslate_context(const char *in, char **out)
+{
+	int ret;
+	int32_t ret_val;
+	int fd;
+
+	*out = NULL;
+
+	fd = setransd_open();
+	if (fd < 0)
+                return fd;
+	ret = send_request(fd, TRANS_TO_RAW_CONTEXT, in, NULL);
+	if (ret)
+		goto out;
+
+	ret = receive_response(fd, TRANS_TO_RAW_CONTEXT, out, &ret_val);
+	if (ret)
+		goto out;
+
+	ret = ret_val;
+out:
+	close(fd);
+	return ret_val;
+}
+
+
+int
+init_context_translations(void)
+{
+	int ret, fd;
+	int32_t ret_val;
+	char *out = NULL;
+
+	fd = setransd_open();
+	if (fd < 0)
+		return fd;
+
+	ret = send_request(fd, SETRANS_INIT, NULL, NULL);
+	if (ret)
+		goto out;
+
+	ret = receive_response(fd, SETRANS_INIT, &out, &ret_val);
+	free(out);
+	if (!ret)
+		ret = ret_val;
+out:
+	close(fd);
+	return ret;
+}
+
diff -Nur libsetrans-0.1.20.orig/src/setransd.c libsetrans-0.1.20/src/setransd.c
--- libsetrans-0.1.20.orig/src/setransd.c	1970-01-01 00:00:00.000000000 +0000
+++ libsetrans-0.1.20/src/setransd.c	2006-04-25 19:10:36.000000000 +0000
@@ -0,0 +1,510 @@
+/* Copyright (c) 2006 Trusted Computer Solutions, Inc. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <syslog.h>
+#include <selinux/selinux.h>
+
+#include "setrans_internal.h"
+#include "setrans.h"
+
+#ifdef DEBUG
+#define log_debug(fmt, ...) syslog(LOG_DEBUG, fmt, __VA_ARGS__)
+#else
+#define log_debug(fmt, ...) ;
+#endif
+
+int init_translations(void);
+int trans_context(const security_context_t, security_context_t *);
+int untrans_context(const security_context_t, security_context_t *);
+
+#define SETRANSD_PATHNAME "/sbin/setransd"
+
+/* name of program (for error messages) */
+#define SETRANSD_PROGNAME "setransd"
+
+static int sockfd = -1;	/* socket we are listening on */
+
+static int restart_daemon = 0;
+
+static void
+cleanup_exit(int ret)
+{
+	if (sockfd >=0)
+		(void)unlink(SETRANS_UNIX_SOCKET);
+	exit(ret);
+}
+
+
+/*
+ * Convert raw label portion of a security context to translated label
+ * Returns:  0 on success, 1 on failure
+ */
+static int
+raw_to_trans_context(char *in, char **out, char *pcon)
+{
+
+	*out = NULL; 
+
+	/* TODO: Check if MLS clearance (in "pcon") dominates the MLS label
+	 * (in "in").
+	 */
+
+	trans_context(in, out);
+	
+	return 0;
+}
+
+
+/*
+ * Convert translated label of a security context to raw label
+ * Returns:  0 on success, 1 on failure
+ */
+static int
+trans_to_raw_context(char *in, char **out, char *pcon)
+{
+	*out = NULL;
+	
+	/* TODO: Check if MLS clearance (in "pcon") dominates the MLS label
+	 * (in "in").
+	 */
+
+	untrans_context(in, out);
+
+	return 0;
+}
+
+static int
+send_response(int fd, uint32_t function, char *data, int32_t ret_val)
+{
+	struct iovec resp_hdr[3];
+	uint32_t data_size;
+	struct iovec resp_data;
+	ssize_t count;
+
+	if (!data)
+		data = "";
+
+	data_size = strlen(data) + 1;
+
+	resp_hdr[0].iov_base = &function;
+	resp_hdr[0].iov_len = sizeof(function);
+	resp_hdr[1].iov_base = &data_size;
+	resp_hdr[1].iov_len = sizeof(data_size);
+	resp_hdr[2].iov_base = &ret_val;
+	resp_hdr[2].iov_len = sizeof(ret_val);
+
+	log_debug("Response header func=%d size=%d ret_val=%d",
+	          function, data_size, ret_val);
+
+	while (((count = writev(fd, resp_hdr, 3)) < 0) && (errno == EINTR));
+	if (count != (sizeof(function) + sizeof(data_size) + sizeof(ret_val))) {
+		syslog(LOG_ERR, "Failed to write response header");
+		return -1;
+	}
+
+	resp_data.iov_base = data;
+	resp_data.iov_len = data_size;
+
+	log_debug("Response data=%s", data);
+
+	while (((count = writev(fd, &resp_data, 1)) < 0) && (errno == EINTR));
+	if (count < 0 || count != data_size) {
+		syslog(LOG_ERR, "Failed to write response data");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+process_request(int fd, uint32_t function, char *data1, char *data2)
+{
+	int32_t result;
+	char *out = NULL;
+	char *peercon;
+	struct ucred peercred;
+	socklen_t size = sizeof(struct ucred);
+	int ret;
+
+	log_debug("Processing request func=%d data1=%s data2=%s"
+	          , function, data1, data2);
+
+	/* get the context of the requesting process */
+	ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &size);
+	if (ret < 0) {
+		syslog(LOG_ERR, "Failed to get PID of client process");
+		return -1;
+	}
+	ret = getpidcon_raw(peercred.pid, &peercon);
+	if (ret) {
+		syslog(LOG_ERR, "Failed to get context of client process");
+		return -1;
+	}
+
+	switch (function) {
+	case SETRANS_INIT:
+		result = 0;
+		ret = send_response(fd, function, NULL, result);
+		break;
+	case RAW_TO_TRANS_CONTEXT:
+		result = raw_to_trans_context(data1, &out, peercon);
+		ret = send_response(fd, function, out, result);
+		break;
+	case TRANS_TO_RAW_CONTEXT:
+		result = trans_to_raw_context(data1, &out, peercon);
+		ret = send_response(fd, function, out, result);
+		break;
+	default:
+		syslog(LOG_ERR, "Invalid request func=%d", function);
+		ret = -1;
+		break;
+	}
+
+	free(out);
+	freecon(peercon);
+
+	return ret;
+}
+
+static int
+service_request(int fd)
+{
+	struct iovec req_hdr[3];
+	uint32_t function;
+	uint32_t data1_size;
+	uint32_t data2_size;
+	struct iovec req_data[2];
+	char *data1;
+	char *data2;
+	int ret;
+	ssize_t count;
+
+	req_hdr[0].iov_base = &function;
+	req_hdr[0].iov_len = sizeof(function);
+	req_hdr[1].iov_base = &data1_size;
+	req_hdr[1].iov_len = sizeof(data1_size);
+	req_hdr[2].iov_base = &data2_size;
+	req_hdr[2].iov_len = sizeof(data2_size);
+
+	while (((count = readv(fd, req_hdr, 3)) < 0) && (errno == EINTR));
+	if (!count) {
+		log_debug("Received no data for fd (%d)", fd);
+		return 1;
+	}
+	if (count != (sizeof(function) + sizeof(data1_size) +
+	              sizeof(data2_size) )) {
+		syslog(LOG_ERR, "Failed to read request header");
+		return -1;
+	}
+
+	log_debug("Received header func=%d size1=%d size2=%d"
+	          , function, data1_size, data2_size);
+
+	if (!data1_size || !data2_size) {
+		syslog(LOG_ERR, "Header invalid data1_size=%d data2_size=%d",
+		        data1_size, data2_size);
+		return -1;
+	}
+
+	data1 = malloc(data1_size);
+	if (!data1) {
+		syslog(LOG_ERR, "Could not allocate %d bytes", data1_size);
+		return -1; 
+	}
+	data2 = malloc(data2_size);
+	if (!data2) {
+		free(data1);
+		syslog(LOG_ERR, "Could not allocate %d bytes", data2_size);
+		return -1;
+	}
+
+	req_data[0].iov_base = data1;
+	req_data[0].iov_len = data1_size;
+	req_data[1].iov_base = data2;
+	req_data[1].iov_len = data2_size;
+
+	while (((count = readv(fd, req_data, 2)) < 0) && (errno == EINTR));
+	if (count < 0 || count != (data1_size + data2_size) ||
+	    data1[data1_size - 1] != '\0' || data2[data2_size - 1] != '\0') {
+		free(data1);
+		free(data2);
+		syslog(LOG_ERR, "Failed to read request data");
+		return -1;
+	}
+
+	log_debug("Received data1=%s data2=%s", data1, data2);
+
+	ret = process_request(fd, function, data1, data2);
+
+	free(data1);
+	free(data2);
+
+	return ret;
+}
+
+static int
+add_pollfd(struct pollfd **ufds, int *nfds, int connfd)
+{
+	int ii = 0;
+
+	/* First see if we can find an already invalidated ufd */
+	for (ii = 0; ii < *nfds; ii++) {
+		if ((*ufds)[ii].fd == -1)
+			break;
+	}
+
+	if (ii == *nfds) {
+		struct pollfd *tmp = (struct pollfd *)realloc(*ufds,
+					(*nfds+1)*sizeof(struct pollfd));
+		if (!tmp) {
+			syslog(LOG_ERR, "realloc failed for %d fds", *nfds+1);
+			return -1;
+		}
+
+		*ufds = tmp;
+		(*nfds)++;
+	}
+
+	(*ufds)[ii].fd = connfd;
+	(*ufds)[ii].events = POLLIN|POLLPRI;
+	(*ufds)[ii].revents = 0;
+
+	return 0;
+}
+
+static void
+adj_pollfds(struct pollfd **ufds, int *nfds)
+{
+	int ii, jj;
+
+	jj = 0;
+	for (ii = 0; ii < *nfds; ii++) {
+		if ((*ufds)[ii].fd != -1) {
+			if (jj < ii)
+				(*ufds)[jj] = (*ufds)[ii];
+			jj++;
+		}
+	}
+	*nfds = jj;
+}
+
+static int
+process_events(struct pollfd **ufds, int *nfds)
+{
+	int ii = 0;
+	int ret = 0;
+
+	for (ii = 0; ii < *nfds; ii++) {
+		short revents = (*ufds)[ii].revents;
+		int connfd = (*ufds)[ii].fd;
+
+		log_debug("Events returned for fd (%d) are (%x)",
+		          connfd, revents);
+
+		if (revents & (POLLIN | POLLPRI)) {
+			if (connfd == sockfd) {
+
+				/* Probably received a connection */
+				if ((connfd = accept(sockfd, NULL, NULL)) < 0) {
+					syslog(LOG_ERR, "accept() failed: %m");
+					return -1;
+				}
+
+				log_debug("Accepted connection with fd (%d)",
+					 connfd);
+
+				if (add_pollfd(ufds, nfds, connfd)) {
+					syslog(LOG_ERR, "Failed to add fd (%d) to poll list", connfd);
+					return -1;
+				}
+			} else {
+				ret = service_request(connfd);
+				if (ret) {
+					if (ret < 0) {
+						syslog(LOG_ERR, "Servicing of request failed "
+						   "for fd (%d)", connfd);
+					}
+					/* Set the pollfd up for deletion later. */
+					(*ufds)[ii].fd = -1;
+					close(connfd);
+				}
+			}
+			revents = revents & ~(POLLIN | POLLPRI);
+		}
+		if (revents & POLLHUP) {
+			log_debug("The connection with fd (%d) hung up", connfd);
+
+			/* Set the pollfd up for deletion later. */
+			(*ufds)[ii].fd = -1;
+			close(connfd);
+
+			revents = revents & ~(POLLHUP);
+		}
+		if (revents) {
+			syslog(LOG_ERR, "Unknown/error events (%x) encountered"
+					" for fd (%d)", revents, connfd);
+
+			/* Set the pollfd up for deletion later. */
+			(*ufds)[ii].fd = -1;
+			close(connfd);
+		}
+
+		(*ufds)[ii].revents = 0;
+	}
+
+	/* Delete any invalidated ufds */
+	adj_pollfds(ufds, nfds);
+
+	return 0;
+}
+
+static void
+process_connections(void)
+{
+	int ret = 0;
+	struct pollfd *ufds;
+	int nfds;
+
+	ufds = (struct pollfd *)malloc(sizeof(struct pollfd));
+	if (!ufds) {
+		syslog(LOG_ERR, "Failed to allocate a pollfd");
+		cleanup_exit(1);
+	}
+	ufds[0].fd = sockfd;
+	ufds[0].events = POLLIN|POLLPRI;
+	ufds[0].revents = 0;
+	nfds = 1;
+
+	while (1) {
+		if (restart_daemon) {
+			(void)unlink(SETRANS_UNIX_SOCKET);
+			execl(SETRANSD_PATHNAME, SETRANSD_PATHNAME, (char *)NULL);
+			syslog(LOG_ERR, "Failed to restart");
+			cleanup_exit(1);
+		}
+
+		log_debug("About to poll for %d fds", nfds);
+		ret = poll(ufds, nfds, -1);
+		if (ret < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			syslog(LOG_ERR, "poll() failed: %m");
+			cleanup_exit(1);
+		}
+
+		ret = process_events(&ufds, &nfds);
+		if (ret) {
+			syslog(LOG_ERR, "Error processing events");
+			cleanup_exit(1);
+		}
+	}
+}
+
+static void
+sigterm_handler(int sig)
+{
+	cleanup_exit(0);
+}
+
+static void
+sighup_handler(int sig)
+{
+	restart_daemon = 1;
+}
+
+static void
+initialize(void)
+{
+	struct sigaction act;
+	struct sockaddr_un addr;
+
+	if (init_translations()) {
+		syslog(LOG_ERR, "Failed to initialize label translations");
+		cleanup_exit(1);
+	}
+
+	/* the socket will be unlinked when the daemon terminates */
+	act.sa_handler = sigterm_handler;
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask, SIGINT);
+	sigaddset(&act.sa_mask, SIGQUIT);
+	sigaddset(&act.sa_mask, SIGTERM);
+	sigaddset(&act.sa_mask, SIGHUP);
+	act.sa_flags = 0;
+	sigaction(SIGINT, &act, NULL);
+	sigaction(SIGQUIT, &act, NULL);
+	sigaction(SIGTERM, &act, NULL);
+
+	/* restart the daemon on SIGHUP */
+	act.sa_handler = sighup_handler;
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask, SIGINT);
+	sigaddset(&act.sa_mask, SIGQUIT);
+	sigaddset(&act.sa_mask, SIGTERM);
+	act.sa_flags = 0;
+	sigaction(SIGHUP, &act, NULL);
+
+	/* ignore SIGPIPE (in case a client terminates after sending request) */
+	act.sa_handler = SIG_IGN;
+	sigemptyset(&act.sa_mask);
+	act.sa_flags = 0;
+	sigaction(SIGPIPE, &act, NULL);
+
+	sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (sockfd < 0)	{
+		syslog(LOG_ERR, "socket() failed: %m");
+		cleanup_exit(1);
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, SETRANS_UNIX_SOCKET, sizeof(addr.sun_path) - 1);
+
+	(void)unlink(SETRANS_UNIX_SOCKET);
+
+	if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		syslog(LOG_ERR, "bind() failed: %m");
+		cleanup_exit(1);
+	}
+
+	if (listen(sockfd, SOMAXCONN) < 0) {
+		syslog(LOG_ERR, "listen() failed: %m");
+		cleanup_exit(1);
+	}
+
+	if (chmod(SETRANS_UNIX_SOCKET, S_IRWXU | S_IRWXG | S_IRWXO)) {
+		syslog(LOG_ERR, "chmod() failed: %m");
+		cleanup_exit(1);
+	}
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	openlog(SETRANSD_PROGNAME, 0, LOG_DAEMON);
+
+	/* run in the background as a daemon */
+	if (daemon(0, 0)) {
+		syslog(LOG_ERR, "daemon() failed: %m");
+		exit(1);
+	}
+
+	initialize();
+
+	process_connections();
+
+	/* we should never get here */
+	return 1;
+}
diff -Nur libsetrans-0.1.20.orig/src/setrans_internal.h libsetrans-0.1.20/src/setrans_internal.h
--- libsetrans-0.1.20.orig/src/setrans_internal.h	1970-01-01 00:00:00.000000000 +0000
+++ libsetrans-0.1.20/src/setrans_internal.h	2006-04-25 19:08:15.000000000 +0000
@@ -0,0 +1,8 @@
+/* Copyright (c) 2006 Trusted Computer Solutions, Inc. */
+
+#define SETRANS_UNIX_SOCKET "/var/.setrans-unix"
+
+#define SETRANS_INIT		1
+#define RAW_TO_TRANS_CONTEXT		2
+#define TRANS_TO_RAW_CONTEXT		3
+
-------------- next part --------------
--- rc.sysinit.orig	2006-03-14 22:50:20.000000000 +0000
+++ rc.sysinit	2006-04-24 16:40:58.000000000 +0000
@@ -419,6 +419,11 @@
 # filesystems are NOT unmounted in single user mode.
 action $"Mounting local filesystems: " mount -a -t nonfs,nfs4,smbfs,ncpfs,cifs,gfs -O no_netdev
 
+# Start the setransd if available
+if [ -x /sbin/setransd ]; then
+    action $"Starting setransd: " /sbin/setransd
+fi
+
 if [ -x /sbin/quotaon ]; then
     action $"Enabling local filesystem quotas: " /sbin/quotaon -aug
 fi
-------------- next part --------------
diff -Nur serefpolicy-2.2.29.orig/policy/modules/kernel/domain.te serefpolicy-2.2.29/policy/modules/kernel/domain.te
--- serefpolicy-2.2.29.orig/policy/modules/kernel/domain.te	2006-03-31 16:11:34.000000000 +0000
+++ serefpolicy-2.2.29/policy/modules/kernel/domain.te	2006-04-25 18:43:30.000000000 +0000
@@ -87,6 +87,8 @@
 # list the root directory
 files_list_root(domain)
 
+setrans_translate_context(domain)
+
 ifdef(`targeted_policy',`
 	# RBAC is disabled in the targeted policy,
 	# as only one role is used, system_r.
diff -Nur serefpolicy-2.2.29.orig/policy/modules/kernel/mls.te serefpolicy-2.2.29/policy/modules/kernel/mls.te
--- serefpolicy-2.2.29.orig/policy/modules/kernel/mls.te	2006-04-13 15:48:25.000000000 +0000
+++ serefpolicy-2.2.29/policy/modules/kernel/mls.te	2006-04-25 18:42:21.000000000 +0000
@@ -63,4 +63,5 @@
 range_transition secadm_t auditctl_exec_t s15:c0.c255;
 range_transition kernel_t init_exec_t s0 - s15:c0.c255;
 range_transition kernel_t lvm_exec_t s0 - s15:c0.c255;
+range_transition initrc_t setrans_exec_t s15:c0.c255;
 ')
-------------- next part --------------

policy_module(setrans,1.0.0)

########################################
#
# Declarations
#

type setrans_t;
type setrans_exec_t;
init_daemon_domain(setrans_t, setrans_exec_t)

mls_file_read_up(setrans_t)
mls_file_write_down(setrans_t)
mls_net_receive_all_levels(setrans_t)
mls_rangetrans_target(setrans_t)

type setrans_unix_stream_t;
files_type(setrans_unix_stream_t)

mls_trusted_object(setrans_unix_stream_t)


########################################
#
# setrans local policy
#

init_use_fds(setrans_t)
kernel_read_kernel_sysctls(setrans_t)
kernel_read_proc_symlinks(setrans_t)
allow setrans_t self:process signal_perms;

libs_use_ld_so(setrans_t)
libs_use_shared_libs(setrans_t)

# create unix domain socket in /var
allow setrans_t var_t:dir rw_dir_perms;
allow setrans_t setrans_unix_stream_t:sock_file create_file_perms;
type_transition setrans_t var_t:sock_file setrans_unix_stream_t;

allow setrans_t self:unix_stream_socket create_stream_socket_perms;

allow setrans_t self:unix_dgram_socket create_socket_perms;
allow setrans_t self:netlink_selinux_socket create_socket_perms;

miscfiles_read_localization(setrans_t)

seutil_read_config(setrans_t)

selinux_compute_access_vector(setrans_t)

files_read_etc_runtime_files(setrans_t)

# allow performing getpidcon() on all processes
domain_read_all_domains_state(setrans_t)
#allow setrans_t domain:{ sock_file fifo_file } r_file_perms;
domain_getattr_all_domains(setrans_t)
domain_getsession_all_domains(setrans_t)

corecmd_search_sbin(setrans_t)
can_exec(setrans_t, setrans_exec_t)

logging_send_syslog_msg(setrans_t)
-------------- next part --------------

/sbin/setransd		--	gen_context(system_u:object_r:setrans_exec_t,s0)

/var/.setrans-unix	--	gen_context(system_u:object_r:setrans_unix_stream_t,s15:c0.c255)
-------------- next part --------------
## <summary>Policy for setrans.</summary>

#######################################
## <summary>
##	Allow a domain to translate contexts.
## </summary>
## <param name="domain">
##	<summary>
##	The type of the process performing this action.
##	</summary>
## </param>
#
interface(`setrans_translate_context',`
	gen_require(`
		type setrans_t, setrans_unix_stream_t;
	')

	allow $1 self:unix_stream_socket create_stream_socket_perms;
	allow $1 setrans_t:unix_stream_socket connectto;
	files_search_var($1)
	allow $1 setrans_unix_stream_t:sock_file rw_file_perms;
	allow $1 setrans_unix_stream_t:unix_stream_socket rw_socket_perms;
')


More information about the redhat-lspp mailing list