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