mcstransd.c revision 7e0f0124743d241354afa888f3bfe23355679bc9
1/* Copyright (c) 2006 Trusted Computer Solutions, Inc. */ 2 3#include <sys/types.h> 4#include <sys/socket.h> 5#include <sys/poll.h> 6#include <sys/stat.h> 7#include <sys/un.h> 8#include <errno.h> 9#include <stdint.h> 10#include <stdio.h> 11#include <unistd.h> 12#include <stdlib.h> 13#include <signal.h> 14#include <string.h> 15#include <syslog.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 47extern int init_translations(void); 48extern void finish_context_translations(void); 49extern int trans_context(const security_context_t, security_context_t *); 50extern int untrans_context(const security_context_t, security_context_t *); 51 52extern int init_colors(void); 53extern void finish_context_colors(void); 54extern 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 61static int sockfd = -1; /* socket we are listening on */ 62 63static volatile int restart_daemon = 0; 64static void cleanup_exit(int ret) __attribute__ ((noreturn)); 65static void 66cleanup_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 78static void clean_exit(void); 79static __attribute__((noreturn)) void clean_exit(void) 80{ 81 log_debug("%s\n", "clean_exit"); 82 cleanup_exit(0); 83} 84 85static int 86send_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 123static int 124get_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 141static int 142get_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 159static int 160process_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 211static int 212service_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 284static int 285add_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 314static void 315adj_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 330static int 331process_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 401static void 402process_connections(void) __attribute__ ((noreturn)); 403 404static void 405process_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 452static void 453sigterm_handler(int sig) __attribute__ ((noreturn)); 454 455static void 456sigterm_handler(int UNUSED(sig)) 457{ 458 cleanup_exit(0); 459} 460 461static void 462sighup_handler(int UNUSED(sig)) 463{ 464 restart_daemon = 1; 465} 466 467static void 468initialize(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 546void 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 559int 560main(int UNUSED(argc), char *argv[]) 561{ 562#ifndef DEBUG 563 /* Make sure we are root */ 564 if (getuid() != 0) { 565 syslog(LOG_ERR, "You must be root to run this program.\n"); 566 return 4; 567 } 568#endif 569 570 openlog(SETRANSD_PROGNAME, 0, LOG_DAEMON); 571 syslog(LOG_NOTICE, "%s starting", argv[0]); 572 573 initialize(); 574 575#ifndef DEBUG 576 dropprivs(); 577 578 /* run in the background as a daemon */ 579 if (daemon(0, 0)) { 580 syslog(LOG_ERR, "daemon() failed: %m"); 581 cleanup_exit(1); 582 } 583#endif 584 585 syslog(LOG_NOTICE, "%s initialized", argv[0]); 586 process_connections(); 587 588 /* we should never get here */ 589 return 1; 590} 591 592