• 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 	char *peercon = NULL;
146 	int ret;
147 
148 	ret = getpeercon_raw(fd, &peercon);
149 	if (ret < 0)
150 		return ret;
151 
152 	/* TODO: Check if MLS clearance (in peercon) dominates the MLS label
153 	 * (in the request input).
154 	 */
155 
156 	switch (function) {
157 	case SETRANS_INIT:
158 		result = 0;
159 		ret = send_response(fd, function, NULL, result);
160 		break;
161 	case RAW_TO_TRANS_CONTEXT:
162 		result = trans_context(data1, &out);
163 		ret = send_response(fd, function, out, result);
164 		break;
165 	case TRANS_TO_RAW_CONTEXT:
166 		result = untrans_context(data1, &out);
167 		ret = send_response(fd, function, out, result);
168 		break;
169 	case RAW_CONTEXT_TO_COLOR:
170 		result = raw_color(data1, &out);
171 		ret = send_response(fd, function, out, result);
172 		break;
173 	default:
174 		result = -1;
175 		ret = -1;
176 		break;
177 	}
178 
179 	if (result) {
180 		pid_t pid = 0;
181 		get_peer_pid(fd, &pid);
182 		syslog(LOG_ERR, "Invalid request func=%d from=%u",
183 		       function, pid);
184 	}
185 
186 	free(out);
187 	freecon(peercon);
188 
189 	return ret;
190 }
191 
192 static int
service_request(int fd)193 service_request(int fd)
194 {
195 	struct iovec req_hdr[3];
196 	uint32_t function;
197 	uint32_t data1_size;
198 	uint32_t data2_size;
199 	struct iovec req_data[2];
200 	char *data1;
201 	char *data2;
202 	int ret;
203 	ssize_t count;
204 
205 	req_hdr[0].iov_base = &function;
206 	req_hdr[0].iov_len = sizeof(function);
207 	req_hdr[1].iov_base = &data1_size;
208 	req_hdr[1].iov_len = sizeof(data1_size);
209 	req_hdr[2].iov_base = &data2_size;
210 	req_hdr[2].iov_len = sizeof(data2_size);
211 
212 	while (((count = readv(fd, req_hdr, 3)) < 0) && (errno == EINTR));
213 	if (count <= 0) {
214 		return 1;
215 	}
216 	if (count != (sizeof(function) + sizeof(data1_size) +
217 	              sizeof(data2_size) )) {
218 		log_debug("Failed to read request header %d != %u\n",(int)count,
219 			(unsigned)(sizeof(function) + sizeof(data1_size) +
220                       sizeof(data2_size) ));
221 		return -1;
222 	}
223 
224 	if (!data1_size || !data2_size || data1_size > MAX_DATA_BUF ||
225 						data2_size > MAX_DATA_BUF ) {
226 		log_debug("Header invalid data1_size=%u data2_size=%u\n",
227 		        data1_size, data2_size);
228 		return -1;
229 	}
230 
231 	data1 = malloc(data1_size);
232 	if (!data1) {
233 		log_debug("Could not allocate %d bytes\n", data1_size);
234 		return -1;
235 	}
236 	data2 = malloc(data2_size);
237 	if (!data2) {
238 		free(data1);
239 		log_debug("Could not allocate %d bytes\n", data2_size);
240 		return -1;
241 	}
242 
243 	req_data[0].iov_base = data1;
244 	req_data[0].iov_len = data1_size;
245 	req_data[1].iov_base = data2;
246 	req_data[1].iov_len = data2_size;
247 
248 	while (((count = readv(fd, req_data, 2)) < 0) && (errno == EINTR));
249 	if (count <= 0 || (size_t)count != (data1_size + data2_size) ||
250 	    data1[data1_size - 1] != '\0' || data2[data2_size - 1] != '\0') {
251 		free(data1);
252 		free(data2);
253 		log_debug("Failed to read request data (%d)\n", (int)count);
254 		return -1;
255 	}
256 
257 	ret = process_request(fd, function, data1, data2);
258 
259 	free(data1);
260 	free(data2);
261 
262 	return ret;
263 }
264 
265 static int
add_pollfd(struct pollfd ** ufds,int * nfds,int connfd)266 add_pollfd(struct pollfd **ufds, int *nfds, int connfd)
267 {
268 	int ii = 0;
269 
270 	/* First see if we can find an already invalidated ufd */
271 	for (ii = 0; ii < *nfds; ii++) {
272 		if ((*ufds)[ii].fd == -1)
273 			break;
274 	}
275 
276 	if (ii == *nfds) {
277 		struct pollfd *tmp = (struct pollfd *)realloc(*ufds,
278 					(*nfds+1)*sizeof(struct pollfd));
279 		if (!tmp) {
280 			syslog(LOG_ERR, "realloc failed for %d fds", *nfds+1);
281 			return -1;
282 		}
283 
284 		*ufds = tmp;
285 		(*nfds)++;
286 	}
287 
288 	(*ufds)[ii].fd = connfd;
289 	(*ufds)[ii].events = POLLIN|POLLPRI;
290 	(*ufds)[ii].revents = 0;
291 
292 	return 0;
293 }
294 
295 static void
adj_pollfds(struct pollfd ** ufds,int * nfds)296 adj_pollfds(struct pollfd **ufds, int *nfds)
297 {
298 	int ii, jj;
299 
300 	jj = 0;
301 	for (ii = 0; ii < *nfds; ii++) {
302 		if ((*ufds)[ii].fd != -1) {
303 			if (jj < ii)
304 				(*ufds)[jj] = (*ufds)[ii];
305 			jj++;
306 		}
307 	}
308 	*nfds = jj;
309 }
310 
311 static int
process_events(struct pollfd ** ufds,int * nfds)312 process_events(struct pollfd **ufds, int *nfds)
313 {
314 	int ii = 0;
315 	int ret = 0;
316 
317 	for (ii = 0; ii < *nfds; ii++) {
318 		short revents = (*ufds)[ii].revents;
319 		int connfd = (*ufds)[ii].fd;
320 
321 		if (revents & (POLLIN | POLLPRI)) {
322 			if (connfd == sockfd) {
323 
324 				/* Probably received a connection */
325 				if ((connfd = accept(sockfd, NULL, NULL)) < 0) {
326 					syslog(LOG_ERR, "accept() failed: %m");
327 					return -1;
328 				}
329 
330 				if (add_pollfd(ufds, nfds, connfd)) {
331 					syslog(LOG_ERR,
332 					  "Failed to add fd (%d) to poll list\n",
333 						connfd);
334 					return -1;
335 				}
336 			} else {
337 				ret = service_request(connfd);
338 				if (ret) {
339 					if (ret < 0) {
340 						syslog(LOG_ERR,
341 							"Servicing of request "
342 							"failed for fd (%d)\n",
343 							connfd);
344 					}
345 					/* Setup pollfd for deletion later. */
346 					(*ufds)[ii].fd = -1;
347 					close(connfd);
348 					/* So we don't get bothered later */
349 					revents = revents & ~(POLLHUP);
350 				}
351 			}
352 			revents = revents & ~(POLLIN | POLLPRI);
353 		}
354 		if (revents & POLLHUP) {
355 			log_debug("The connection with fd (%d) hung up\n",
356 				connfd);
357 
358 			/* Set the pollfd up for deletion later. */
359 			(*ufds)[ii].fd = -1;
360 			close(connfd);
361 
362 			revents = revents & ~(POLLHUP);
363 		}
364 		if (revents) {
365 			syslog(LOG_ERR, "Unknown/error events (%x) encountered"
366 					" for fd (%d)\n", revents, connfd);
367 
368 			/* Set the pollfd up for deletion later. */
369 			(*ufds)[ii].fd = -1;
370 			close(connfd);
371 		}
372 
373 		(*ufds)[ii].revents = 0;
374 	}
375 
376 	/* Delete any invalidated ufds */
377 	adj_pollfds(ufds, nfds);
378 
379 	return 0;
380 }
381 
382 static void
383 process_connections(void) __attribute__ ((noreturn));
384 
385 static void
process_connections(void)386 process_connections(void)
387 {
388 	int ret = 0;
389 	int nfds = 1;
390 
391 	struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd));
392 	if (!ufds) {
393 		syslog(LOG_ERR, "Failed to allocate a pollfd");
394 		cleanup_exit(1);
395 	}
396 	ufds[0].fd = sockfd;
397 	ufds[0].events = POLLIN|POLLPRI;
398 	ufds[0].revents = 0;
399 
400 	while (1) {
401 		if (restart_daemon) {
402 			syslog(LOG_NOTICE, "Reload Translations");
403 			finish_context_colors();
404 			finish_context_translations();
405 			if (init_translations()) {
406 				syslog(LOG_ERR, "Failed to initialize label translations");
407 				cleanup_exit(1);
408 			}
409 			if (init_colors()) {
410 				syslog(LOG_ERR, "Failed to initialize color translations");
411 				syslog(LOG_ERR, "No color information will be available");
412 			}
413 			restart_daemon = 0;
414 		}
415 
416 		ret = poll(ufds, nfds, -1);
417 		if (ret < 0) {
418 			if (errno == EINTR) {
419 				continue;
420 			}
421 			syslog(LOG_ERR, "poll() failed: %m");
422 			cleanup_exit(1);
423 		}
424 
425 		ret = process_events(&ufds, &nfds);
426 		if (ret) {
427 			syslog(LOG_ERR, "Error processing events");
428 			cleanup_exit(1);
429 		}
430 	}
431 }
432 
433 static void
434 sigterm_handler(int sig) __attribute__ ((noreturn));
435 
436 static void
sigterm_handler(int UNUSED (sig))437 sigterm_handler(int UNUSED(sig))
438 {
439 	cleanup_exit(0);
440 }
441 
442 static void
sighup_handler(int UNUSED (sig))443 sighup_handler(int UNUSED(sig))
444 {
445 	restart_daemon = 1;
446 }
447 
448 static void
initialize(void)449 initialize(void)
450 {
451 	struct sigaction act;
452 	struct sockaddr_un addr;
453 	struct rlimit rl ;
454 
455 	if (init_translations()) {
456 		syslog(LOG_ERR, "Failed to initialize label translations");
457 		cleanup_exit(1);
458 	}
459 	if (init_colors()) {
460 		syslog(LOG_ERR, "Failed to initialize color translations");
461 		syslog(LOG_ERR, "No color information will be available");
462 	}
463 
464 	/* the socket will be unlinked when the daemon terminates */
465 	act.sa_handler = sigterm_handler;
466 	sigemptyset(&act.sa_mask);
467 	sigaddset(&act.sa_mask, SIGINT);
468 	sigaddset(&act.sa_mask, SIGQUIT);
469 	sigaddset(&act.sa_mask, SIGTERM);
470 	sigaddset(&act.sa_mask, SIGHUP);
471 	act.sa_flags = 0;
472 	sigaction(SIGINT, &act, NULL);
473 	sigaction(SIGQUIT, &act, NULL);
474 	sigaction(SIGTERM, &act, NULL);
475 
476 	/* restart the daemon on SIGHUP */
477 	act.sa_handler = sighup_handler;
478 	sigemptyset(&act.sa_mask);
479 	sigaddset(&act.sa_mask, SIGINT);
480 	sigaddset(&act.sa_mask, SIGQUIT);
481 	sigaddset(&act.sa_mask, SIGTERM);
482 	act.sa_flags = 0;
483 	sigaction(SIGHUP, &act, NULL);
484 
485 	/* ignore SIGPIPE (in case a client terminates after sending request) */
486 	act.sa_handler = SIG_IGN;
487 	sigemptyset(&act.sa_mask);
488 	act.sa_flags = 0;
489 	sigaction(SIGPIPE, &act, NULL);
490 
491 	atexit(clean_exit);
492 
493 	sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
494 	if (sockfd < 0)	{
495 		syslog(LOG_ERR, "socket() failed: %m");
496 		cleanup_exit(1);
497 	}
498 
499 	memset(&addr, 0, sizeof(addr));
500 	addr.sun_family = AF_UNIX;
501 	strncpy(addr.sun_path, SETRANS_UNIX_SOCKET, sizeof(addr.sun_path) - 1);
502 
503 	(void)unlink(SETRANS_UNIX_SOCKET);
504 
505 	if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
506 		syslog(LOG_ERR, "bind() failed: %m");
507 		cleanup_exit(1);
508 	}
509 
510 	if (listen(sockfd, SOMAXCONN) < 0) {
511 		syslog(LOG_ERR, "listen() failed: %m");
512 		cleanup_exit(1);
513 	}
514 
515 	if (chmod(SETRANS_UNIX_SOCKET, S_IRWXU | S_IRWXG | S_IRWXO)) {
516 		syslog(LOG_ERR, "chmod() failed: %m");
517 		cleanup_exit(1);
518 	}
519 
520 	/* Raise the rlimit for file descriptors... */
521 	rl.rlim_max = MAX_DESCRIPTORS;
522 	rl.rlim_cur = MAX_DESCRIPTORS;
523 	setrlimit(RLIMIT_NOFILE, &rl);
524 
525 }
526 
dropprivs(void)527 void dropprivs(void)
528 {
529 	cap_t new_caps;
530 
531 	new_caps = cap_init();
532 	if (cap_set_proc(new_caps)) {
533 		syslog(LOG_ERR, "Error dropping capabilities, aborting: %s\n",
534 			 strerror(errno));
535 		cleanup_exit(-1);
536 	}
537 	cap_free(new_caps);
538 }
539 
usage(char * program)540 static void usage(char *program)
541 {
542 	printf("%s [-f] [-h] \n", program);
543 }
544 
545 int
main(int argc,char * argv[])546 main(int argc, char *argv[])
547 {
548 	int opt;
549 	int do_fork = 1;
550 	while ((opt = getopt(argc, argv, "hf")) > 0) {
551 		switch (opt) {
552 		case 'f':
553 			do_fork = 0;
554 			break;
555 		case 'h':
556 			usage(argv[0]);
557 			exit(0);
558 			break;
559 		case '?':
560 			usage(argv[0]);
561 			exit(-1);
562 		}
563 	}
564 
565 #ifndef DEBUG
566 	/* Make sure we are root */
567 	if (getuid() != 0) {
568 		syslog(LOG_ERR, "You must be root to run this program.\n");
569 		return 4;
570 	}
571 #endif
572 
573 	openlog(SETRANSD_PROGNAME, 0, LOG_DAEMON);
574 	syslog(LOG_NOTICE, "%s starting", argv[0]);
575 
576 	initialize();
577 
578 #ifndef DEBUG
579 	dropprivs();
580 
581 	/* run in the background as a daemon */
582 	if (do_fork && daemon(0, 0)) {
583 		syslog(LOG_ERR, "daemon() failed: %m");
584 		cleanup_exit(1);
585 	}
586 #endif
587 
588 	syslog(LOG_NOTICE, "%s initialized", argv[0]);
589 	process_connections();
590 
591 	/* we should never get here */
592 	return 1;
593 }
594 
595