• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2006 Trusted Computer Solutions, Inc. */
2 #include <errno.h>
3 #include <poll.h>
4 #include <signal.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <syslog.h>
10 #include <unistd.h>
11 #include <selinux/selinux.h>
12 #include <sys/capability.h>
13 #include <sys/resource.h>
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/uio.h>
18 #include <sys/un.h>
19 #include "mcstrans.h"
20 
21 #ifdef UNUSED
22 #elif defined(__GNUC__)
23 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
24 #elif defined(__LCLINT__)
25 # define UNUSED(x) /*@unused@*/ x
26 #else
27 # define UNUSED(x) x
28 #endif
29 
30 #define SETRANS_UNIX_SOCKET "/var/run/setrans/.setrans-unix"
31 
32 #define SETRANS_INIT			1
33 #define RAW_TO_TRANS_CONTEXT		2
34 #define TRANS_TO_RAW_CONTEXT		3
35 #define RAW_CONTEXT_TO_COLOR		4
36 #define MAX_DATA_BUF			4096
37 #define MAX_DESCRIPTORS			8192
38 
39 #ifdef DEBUG
40 //#define log_debug(fmt, ...) syslog(LOG_DEBUG, fmt, __VA_ARGS__)
41 #define log_debug(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
42 #else
43 #define log_debug(fmt, ...) ;
44 #endif
45 
46 extern int init_translations(void);
47 extern void finish_context_translations(void);
48 extern int trans_context(const security_context_t, security_context_t *);
49 extern int untrans_context(const security_context_t, security_context_t *);
50 
51 extern int init_colors(void);
52 extern void finish_context_colors(void);
53 extern int raw_color(const security_context_t, char **);
54 
55 #define SETRANSD_PATHNAME "/sbin/mcstransd"
56 
57 /* name of program (for error messages) */
58 #define SETRANSD_PROGNAME "mcstransd"
59 
60 static int sockfd = -1;	/* socket we are listening on */
61 
62 static volatile int restart_daemon = 0;
63 static void cleanup_exit(int ret) __attribute__ ((noreturn));
64 static void
cleanup_exit(int ret)65 cleanup_exit(int ret)
66 {
67 	finish_context_colors();
68 	finish_context_translations();
69 	if (sockfd >=0)
70 		(void)unlink(SETRANS_UNIX_SOCKET);
71 
72 	log_debug("%s\n", "cleanup_exit");
73 
74 	exit(ret);
75 }
76 
77 static void clean_exit(void);
clean_exit(void)78 static  __attribute__((noreturn)) void clean_exit(void)
79 {
80 	log_debug("%s\n", "clean_exit");
81 	cleanup_exit(0);
82 }
83 
84 static int
send_response(int fd,uint32_t function,char * data,int32_t ret_val)85 send_response(int fd, uint32_t function, char *data, int32_t ret_val)
86 {
87 	struct iovec resp_hdr[3];
88 	uint32_t data_size;
89 	struct iovec resp_data;
90 	ssize_t count;
91 
92 	if (!data)
93 		data = (char *)"";
94 
95 	data_size = strlen(data) + 1;
96 
97 	resp_hdr[0].iov_base = &function;
98 	resp_hdr[0].iov_len = sizeof(function);
99 	resp_hdr[1].iov_base = &data_size;
100 	resp_hdr[1].iov_len = sizeof(data_size);
101 	resp_hdr[2].iov_base = &ret_val;
102 	resp_hdr[2].iov_len = sizeof(ret_val);
103 
104 	while (((count = writev(fd, resp_hdr, 3)) < 0) && (errno == EINTR));
105 	if (count != (sizeof(function) + sizeof(data_size) + sizeof(ret_val))) {
106 		syslog(LOG_ERR, "Failed to write response header");
107 		return -1;
108 	}
109 
110 	resp_data.iov_base = data;
111 	resp_data.iov_len = data_size;
112 
113 	while (((count = writev(fd, &resp_data, 1)) < 0) && (errno == EINTR));
114 	if (count < 0 || (size_t)count != data_size) {
115 		syslog(LOG_ERR, "Failed to write response data");
116 		return -1;
117 	}
118 
119 	return ret_val;
120 }
121 
122 static int
get_peer_pid(int fd,pid_t * pid)123 get_peer_pid(int fd, pid_t *pid)
124 {
125 	int ret;
126 	socklen_t size = sizeof(struct ucred);
127 	struct ucred peercred;
128 
129 	/* get the context of the requesting process */
130 	ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &size);
131 	if (ret < 0) {
132 		syslog(LOG_ERR, "Failed to get PID of client process");
133 		return -1;
134 	}
135 	*pid = peercred.pid;
136 	return ret;
137 }
138 
139 
140 static int
process_request(int fd,uint32_t function,char * data1,char * UNUSED (data2))141 process_request(int fd, uint32_t function, char *data1, char *UNUSED(data2))
142 {
143 	int32_t result;
144 	char *out = NULL;
145 	int ret;
146 
147 	switch (function) {
148 	case SETRANS_INIT:
149 		result = 0;
150 		ret = send_response(fd, function, NULL, result);
151 		break;
152 	case RAW_TO_TRANS_CONTEXT:
153 		result = trans_context(data1, &out);
154 		ret = send_response(fd, function, out, result);
155 		break;
156 	case TRANS_TO_RAW_CONTEXT:
157 		result = untrans_context(data1, &out);
158 		ret = send_response(fd, function, out, result);
159 		break;
160 	case RAW_CONTEXT_TO_COLOR:
161 		result = raw_color(data1, &out);
162 		ret = send_response(fd, function, out, result);
163 		break;
164 	default:
165 		result = -1;
166 		ret = -1;
167 		break;
168 	}
169 
170 	if (result) {
171 		pid_t pid = 0;
172 		get_peer_pid(fd, &pid);
173 		syslog(LOG_ERR, "Invalid request func=%d from=%u",
174 		       function, pid);
175 	}
176 
177 	free(out);
178 
179 	return ret;
180 }
181 
182 static int
service_request(int fd)183 service_request(int fd)
184 {
185 	struct iovec req_hdr[3];
186 	uint32_t function;
187 	uint32_t data1_size;
188 	uint32_t data2_size;
189 	struct iovec req_data[2];
190 	char *data1;
191 	char *data2;
192 	int ret;
193 	ssize_t count;
194 
195 	req_hdr[0].iov_base = &function;
196 	req_hdr[0].iov_len = sizeof(function);
197 	req_hdr[1].iov_base = &data1_size;
198 	req_hdr[1].iov_len = sizeof(data1_size);
199 	req_hdr[2].iov_base = &data2_size;
200 	req_hdr[2].iov_len = sizeof(data2_size);
201 
202 	while (((count = readv(fd, req_hdr, 3)) < 0) && (errno == EINTR));
203 	if (count <= 0) {
204 		return 1;
205 	}
206 	if (count != (sizeof(function) + sizeof(data1_size) +
207 	              sizeof(data2_size) )) {
208 		log_debug("Failed to read request header %d != %u\n",(int)count,
209 			(unsigned)(sizeof(function) + sizeof(data1_size) +
210                       sizeof(data2_size) ));
211 		return -1;
212 	}
213 
214 	if (!data1_size || !data2_size || data1_size > MAX_DATA_BUF ||
215 						data2_size > MAX_DATA_BUF ) {
216 		log_debug("Header invalid data1_size=%u data2_size=%u\n",
217 		        data1_size, data2_size);
218 		return -1;
219 	}
220 
221 	data1 = malloc(data1_size);
222 	if (!data1) {
223 		log_debug("Could not allocate %d bytes\n", data1_size);
224 		return -1;
225 	}
226 	data2 = malloc(data2_size);
227 	if (!data2) {
228 		free(data1);
229 		log_debug("Could not allocate %d bytes\n", data2_size);
230 		return -1;
231 	}
232 
233 	req_data[0].iov_base = data1;
234 	req_data[0].iov_len = data1_size;
235 	req_data[1].iov_base = data2;
236 	req_data[1].iov_len = data2_size;
237 
238 	while (((count = readv(fd, req_data, 2)) < 0) && (errno == EINTR));
239 	if (count <= 0 || (size_t)count != (data1_size + data2_size) ||
240 	    data1[data1_size - 1] != '\0' || data2[data2_size - 1] != '\0') {
241 		free(data1);
242 		free(data2);
243 		log_debug("Failed to read request data (%d)\n", (int)count);
244 		return -1;
245 	}
246 
247 	ret = process_request(fd, function, data1, data2);
248 
249 	free(data1);
250 	free(data2);
251 
252 	return ret;
253 }
254 
255 static int
add_pollfd(struct pollfd ** ufds,int * nfds,int connfd)256 add_pollfd(struct pollfd **ufds, int *nfds, int connfd)
257 {
258 	int ii = 0;
259 
260 	/* First see if we can find an already invalidated ufd */
261 	for (ii = 0; ii < *nfds; ii++) {
262 		if ((*ufds)[ii].fd == -1)
263 			break;
264 	}
265 
266 	if (ii == *nfds) {
267 		struct pollfd *tmp = (struct pollfd *)realloc(*ufds,
268 					(*nfds+1)*sizeof(struct pollfd));
269 		if (!tmp) {
270 			syslog(LOG_ERR, "realloc failed for %d fds", *nfds+1);
271 			return -1;
272 		}
273 
274 		*ufds = tmp;
275 		(*nfds)++;
276 	}
277 
278 	(*ufds)[ii].fd = connfd;
279 	(*ufds)[ii].events = POLLIN|POLLPRI;
280 	(*ufds)[ii].revents = 0;
281 
282 	return 0;
283 }
284 
285 static void
adj_pollfds(struct pollfd ** ufds,int * nfds)286 adj_pollfds(struct pollfd **ufds, int *nfds)
287 {
288 	int ii, jj;
289 
290 	jj = 0;
291 	for (ii = 0; ii < *nfds; ii++) {
292 		if ((*ufds)[ii].fd != -1) {
293 			if (jj < ii)
294 				(*ufds)[jj] = (*ufds)[ii];
295 			jj++;
296 		}
297 	}
298 	*nfds = jj;
299 }
300 
301 static int
process_events(struct pollfd ** ufds,int * nfds)302 process_events(struct pollfd **ufds, int *nfds)
303 {
304 	int ii = 0;
305 	int ret = 0;
306 
307 	for (ii = 0; ii < *nfds; ii++) {
308 		short revents = (*ufds)[ii].revents;
309 		int connfd = (*ufds)[ii].fd;
310 
311 		if (revents & (POLLIN | POLLPRI)) {
312 			if (connfd == sockfd) {
313 
314 				/* Probably received a connection */
315 				if ((connfd = accept(sockfd, NULL, NULL)) < 0) {
316 					syslog(LOG_ERR, "accept() failed: %m");
317 					return -1;
318 				}
319 
320 				if (add_pollfd(ufds, nfds, connfd)) {
321 					syslog(LOG_ERR,
322 					  "Failed to add fd (%d) to poll list\n",
323 						connfd);
324 					return -1;
325 				}
326 			} else {
327 				ret = service_request(connfd);
328 				if (ret) {
329 					if (ret < 0) {
330 						syslog(LOG_ERR,
331 							"Servicing of request "
332 							"failed for fd (%d)\n",
333 							connfd);
334 					}
335 					/* Setup pollfd for deletion later. */
336 					(*ufds)[ii].fd = -1;
337 					close(connfd);
338 					/* So we don't get bothered later */
339 					revents = revents & ~(POLLHUP);
340 				}
341 			}
342 			revents = revents & ~(POLLIN | POLLPRI);
343 		}
344 		if (revents & POLLHUP) {
345 			log_debug("The connection with fd (%d) hung up\n",
346 				connfd);
347 
348 			/* Set the pollfd up for deletion later. */
349 			(*ufds)[ii].fd = -1;
350 			close(connfd);
351 
352 			revents = revents & ~(POLLHUP);
353 		}
354 		if (revents) {
355 			syslog(LOG_ERR, "Unknown/error events (%x) encountered"
356 					" for fd (%d)\n", revents, connfd);
357 
358 			/* Set the pollfd up for deletion later. */
359 			(*ufds)[ii].fd = -1;
360 			close(connfd);
361 		}
362 
363 		(*ufds)[ii].revents = 0;
364 	}
365 
366 	/* Delete any invalidated ufds */
367 	adj_pollfds(ufds, nfds);
368 
369 	return 0;
370 }
371 
372 static void
373 process_connections(void) __attribute__ ((noreturn));
374 
375 static void
process_connections(void)376 process_connections(void)
377 {
378 	int ret = 0;
379 	int nfds = 1;
380 
381 	struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd));
382 	if (!ufds) {
383 		syslog(LOG_ERR, "Failed to allocate a pollfd");
384 		cleanup_exit(1);
385 	}
386 	ufds[0].fd = sockfd;
387 	ufds[0].events = POLLIN|POLLPRI;
388 	ufds[0].revents = 0;
389 
390 	while (1) {
391 		if (restart_daemon) {
392 			syslog(LOG_NOTICE, "Reload Translations");
393 			finish_context_colors();
394 			finish_context_translations();
395 			if (init_translations()) {
396 				syslog(LOG_ERR, "Failed to initialize label translations");
397 				cleanup_exit(1);
398 			}
399 			if (init_colors()) {
400 				syslog(LOG_ERR, "Failed to initialize color translations");
401 				syslog(LOG_ERR, "No color information will be available");
402 			}
403 			restart_daemon = 0;
404 		}
405 
406 		ret = poll(ufds, nfds, -1);
407 		if (ret < 0) {
408 			if (errno == EINTR) {
409 				continue;
410 			}
411 			syslog(LOG_ERR, "poll() failed: %m");
412 			cleanup_exit(1);
413 		}
414 
415 		ret = process_events(&ufds, &nfds);
416 		if (ret) {
417 			syslog(LOG_ERR, "Error processing events");
418 			cleanup_exit(1);
419 		}
420 	}
421 }
422 
423 static void
424 sigterm_handler(int sig) __attribute__ ((noreturn));
425 
426 static void
sigterm_handler(int UNUSED (sig))427 sigterm_handler(int UNUSED(sig))
428 {
429 	cleanup_exit(0);
430 }
431 
432 static void
sighup_handler(int UNUSED (sig))433 sighup_handler(int UNUSED(sig))
434 {
435 	restart_daemon = 1;
436 }
437 
438 static void
initialize(void)439 initialize(void)
440 {
441 	struct sigaction act;
442 	struct sockaddr_un addr;
443 	struct rlimit rl ;
444 
445 	if (init_translations()) {
446 		syslog(LOG_ERR, "Failed to initialize label translations");
447 		cleanup_exit(1);
448 	}
449 	if (init_colors()) {
450 		syslog(LOG_ERR, "Failed to initialize color translations");
451 		syslog(LOG_ERR, "No color information will be available");
452 	}
453 
454 	/* the socket will be unlinked when the daemon terminates */
455 	act.sa_handler = sigterm_handler;
456 	sigemptyset(&act.sa_mask);
457 	sigaddset(&act.sa_mask, SIGINT);
458 	sigaddset(&act.sa_mask, SIGQUIT);
459 	sigaddset(&act.sa_mask, SIGTERM);
460 	sigaddset(&act.sa_mask, SIGHUP);
461 	act.sa_flags = 0;
462 	sigaction(SIGINT, &act, NULL);
463 	sigaction(SIGQUIT, &act, NULL);
464 	sigaction(SIGTERM, &act, NULL);
465 
466 	/* restart the daemon on SIGHUP */
467 	act.sa_handler = sighup_handler;
468 	sigemptyset(&act.sa_mask);
469 	sigaddset(&act.sa_mask, SIGINT);
470 	sigaddset(&act.sa_mask, SIGQUIT);
471 	sigaddset(&act.sa_mask, SIGTERM);
472 	act.sa_flags = 0;
473 	sigaction(SIGHUP, &act, NULL);
474 
475 	/* ignore SIGPIPE (in case a client terminates after sending request) */
476 	act.sa_handler = SIG_IGN;
477 	sigemptyset(&act.sa_mask);
478 	act.sa_flags = 0;
479 	sigaction(SIGPIPE, &act, NULL);
480 
481 	atexit(clean_exit);
482 
483 	sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
484 	if (sockfd < 0)	{
485 		syslog(LOG_ERR, "socket() failed: %m");
486 		cleanup_exit(1);
487 	}
488 
489 	memset(&addr, 0, sizeof(addr));
490 	addr.sun_family = AF_UNIX;
491 	strncpy(addr.sun_path, SETRANS_UNIX_SOCKET, sizeof(addr.sun_path) - 1);
492 
493 	(void)unlink(SETRANS_UNIX_SOCKET);
494 
495 	if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
496 		syslog(LOG_ERR, "bind() failed: %m");
497 		cleanup_exit(1);
498 	}
499 
500 	if (listen(sockfd, SOMAXCONN) < 0) {
501 		syslog(LOG_ERR, "listen() failed: %m");
502 		cleanup_exit(1);
503 	}
504 
505 	if (chmod(SETRANS_UNIX_SOCKET, S_IRWXU | S_IRWXG | S_IRWXO)) {
506 		syslog(LOG_ERR, "chmod() failed: %m");
507 		cleanup_exit(1);
508 	}
509 
510 	/* Raise the rlimit for file descriptors... */
511 	rl.rlim_max = MAX_DESCRIPTORS;
512 	rl.rlim_cur = MAX_DESCRIPTORS;
513 	setrlimit(RLIMIT_NOFILE, &rl);
514 
515 }
516 
dropprivs(void)517 void dropprivs(void)
518 {
519 	cap_t new_caps;
520 
521 	new_caps = cap_init();
522 	if (cap_set_proc(new_caps)) {
523 		syslog(LOG_ERR, "Error dropping capabilities, aborting: %s\n",
524 			 strerror(errno));
525 		cleanup_exit(-1);
526 	}
527 	cap_free(new_caps);
528 }
529 
usage(char * program)530 static void usage(char *program)
531 {
532 	printf("%s [-f] [-h] \n", program);
533 }
534 
535 int
main(int argc,char * argv[])536 main(int argc, char *argv[])
537 {
538 	int opt;
539 	int do_fork = 1;
540 	while ((opt = getopt(argc, argv, "hf")) > 0) {
541 		switch (opt) {
542 		case 'f':
543 			do_fork = 0;
544 			break;
545 		case 'h':
546 			usage(argv[0]);
547 			exit(0);
548 			break;
549 		case '?':
550 			usage(argv[0]);
551 			exit(-1);
552 		}
553 	}
554 
555 #ifndef DEBUG
556 	/* Make sure we are root */
557 	if (getuid() != 0) {
558 		syslog(LOG_ERR, "You must be root to run this program.\n");
559 		return 4;
560 	}
561 #endif
562 
563 	openlog(SETRANSD_PROGNAME, 0, LOG_DAEMON);
564 	syslog(LOG_NOTICE, "%s starting", argv[0]);
565 
566 	initialize();
567 
568 #ifndef DEBUG
569 	dropprivs();
570 
571 	/* run in the background as a daemon */
572 	if (do_fork && daemon(0, 0)) {
573 		syslog(LOG_ERR, "daemon() failed: %m");
574 		cleanup_exit(1);
575 	}
576 #endif
577 
578 	syslog(LOG_NOTICE, "%s initialized", argv[0]);
579 	process_connections();
580 
581 	/* we should never get here */
582 	return 1;
583 }
584 
585