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