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