/* * Constable security daemon for Medusa DS9 security system */ #define __KERNEL__ #include #undef __KERNEL__ #include #include #include #include #include #include #include #include #include #include #include #include #include "constable.h" #define BUFLEN 10240 #ifdef TRAFFIC #undef TRAFFIC #endif int main(int argc, char *argv[]); int init_wrapper(int argc, char *argv[]); int constable(int argc, char *argv[]); char *me = NULL; int medfd; static int null_mod(struct medusa_packet *msg, char *data, struct medusa_packet *ans, char **outdata) { return 0; /* not for me */ } struct c_module modules = { NULL, null_mod }; int add_module(int (*func) (struct medusa_packet *, char *, struct medusa_packet *, char **)) { struct c_module *new; if ((new = malloc(sizeof(struct c_module))) == NULL) fatal(OUTMEM); new->func = func; new->next = modules.next; modules.next = new; return 0; } char *med_cmd(struct medusa_packet *msg, char *data) { static char buf[BUFLEN]; int res; msg->id = 0; msg->answer = MED_OK; if (data != NULL && msg->data_len <= 0) msg->data_len = strlen(data) + 1; if (data == NULL) msg->data_len = 0; res = write(medfd, msg, sizeof(struct medusa_packet)); if (res < 0) { fprintf(stderr, "%s: Command write error: system error code %i\n", me, res); msg->answer = MED_ERR; return NULL; } if (res != sizeof(struct medusa_packet)) { fprintf(stderr, "%s: Command write error: incorrect packet length\n", me); msg->answer = MED_ERR; return NULL; } if (data != NULL) { res = write(medfd, data, msg->data_len); if (res < 0) { fprintf(stderr, "%s: Command data write error: system error code %i\n", me, res); msg->answer = MED_ERR; return NULL; } if (res != msg->data_len) { fprintf(stderr, "%s: Command data write error: incorrect data length\n", me); msg->answer = MED_ERR; return NULL; } } res = read(medfd, msg, sizeof(struct medusa_packet)); if (res < 0) { fprintf(stderr, "%s: Command read error: system error code %i\n", me, res); msg->answer = MED_ERR; return NULL; } if (res != sizeof(struct medusa_packet)) { fprintf(stderr, "%s: Command read error: %s\n", me, strerror(res)); msg->answer = MED_ERR; return NULL; } if (msg->id != 0) { fprintf(stderr, "%s: Command read error: incorrect packet sequence number: terminating...\n", me); close(medfd); exit(-1); } if (msg->data_len > 0) { if (msg->data_len >= BUFLEN) { fprintf(stderr, "%s: Command data read error: data size too big: terminating ...\n", me); /* FIXME! tell kernel to let it be */ close(medfd); exit(-1); } res = read(medfd, buf, msg->data_len); if (res < 0) { fprintf(stderr, "%s: Command data read error: system error code %i\n", me, res); msg->answer = MED_ERR; return NULL; } if (res != msg->data_len) { fprintf(stderr, "%s: Command data read error: incorrect data length\n", me); msg->answer = MED_ERR; return NULL; } buf[msg->data_len] = 0; return buf; } return NULL; } #ifdef MEDUSA_INITNAME int init_wrapper(int argc, char * argv[]) { int i, status; switch ((i = fork())) { case -1: exit(-1); case 0: constable(0, NULL); exit(-1); default: waitpid(i, &status, 0); if (!WIFEXITED(status)) exit(-1); argv[0] = MEDUSA_INITNAME; execvp(argv[0], argv); } return -1; } #endif int main(int argc, char *argv[]) { #ifdef MEDUSA_INITNAME if(getpid() <= 1) return init_wrapper(argc, argv); #endif return constable(argc, argv); } int constable(int argc, char *argv[]) { int res; #ifdef TRAFFIC int ii; #endif struct c_module *mod; struct medusa_packet msg, ans; char *data_from_kernel, *data_to_kernel; struct sched_param schedpar; struct stat statbuf; char *devfile = MEDUSA_DEVFILE, *conffile = MEDUSA_CONFFILE; char bufer[BUFLEN]; me = (argv && argv[0]) ? argv[0] : "constable"; if (argc > 1) { if (!strncmp(argv[1], "--help", 6)) { printf ("Usage: %s [configuration file] [medusa-character device]\n", me); return 0; } conffile = argv[1]; } if (argc > 2) { devfile = argv[2]; } if (modules_preinit(conffile) < 0) return -1; mlockall(MCL_CURRENT | MCL_FUTURE); #ifndef DEBUG switch (fork()) { case 0: setsid(); schedpar.sched_priority = sched_get_priority_max(SCHED_FIFO); sched_setscheduler(0, SCHED_FIFO, &schedpar); break; case -1: return -1; default: return 0; } #endif if (stat(devfile, &statbuf) != 0) { fprintf(stderr, "%s: Error accessing %s: terminating...\n", me, devfile); return -1; } if (!S_ISCHR(statbuf.st_mode)) { fprintf(stderr, "%s: %s is not a character device: terminating...\n", me, devfile); return -1; } if ((medfd = open(devfile, O_RDWR)) < 0) { fprintf(stderr, "%s: Error opening %s: terminating...\n", me, devfile); return -1; } msg.id = 0; /* send supported communcation protocol */ msg.cmd = MED_VERSION; /* version number */ msg.u.r_cmd.arg[0] = 1; /* only one version is now supported :-) */ msg.data_len = 0; med_cmd(&msg, NULL); if (msg.answer == MED_NO) { fprintf(stderr, "%s: Medusa communication protocol version 1 not supported by the kernel: terminating...\n", me); close(medfd); return -1; } if (msg.answer == MED_ERR) { fprintf(stderr, "%s: Error initializing communication interface: terminating...\n", me); close(medfd); return -1; } msg.id = 0; msg.cmd = MED_RESET; msg.data_len = 0; med_cmd(&msg, NULL); if (modules_postinit() < 0) return -1; while (1) { /* fd_set in; FD_ZERO(&in); FD_SET(medfd,&in); select(medfd+1,&in,NULL,NULL,NULL); if( !FD_ISSET(medfd,&in) ) fprintf(stderr, "%s: Read error!\n", me); */ res = read(medfd, &msg, sizeof(msg)); if (res < 0) { fprintf(stderr, "%s: Read error: system error code %i: terminating...\n", me, res); close(medfd); return -1; } if (res != sizeof(msg)) { fprintf(stderr, "%s: Read error: incorrect packet size: terminating ...\n", me); close(medfd); return -1; } ans.id = msg.id; ans.cmd = msg.cmd; ans.answer = MED_ERR; /* get the data if available */ if (msg.data_len > 0) { if (msg.data_len >= BUFLEN) { fprintf(stderr, "%s: Data read error: data size too big: terminating ...\n", me); /* FIXME! tell kernel to let it be */ close(medfd); return -1; } data_from_kernel = bufer; res = read(medfd, data_from_kernel, msg.data_len); if (res != msg.data_len) { fprintf(stderr, "%s: Data read error: system error code %i: terminating...\n", me, res); close(medfd); return -1; } data_from_kernel[msg.data_len] = 0; } else data_from_kernel = NULL; data_to_kernel = NULL; // if( msg.cmd==MED_IACT ) /* to make medinf valid */ // { ans.u.a_iact.proc.pid=0; // if( msg.u.r_iact.inode.ino!=0 && msg.u.r_iact.inode.dev!=0 // && !med_c_valid( &(msg.u.r_iact.inode.mi) ) ) // { files_t *f; // f=files_find_ino( root, msg.u.r_iact.inode.dev, // msg.u.r_iact.inode.ino ); // msg.u.r_iact.inode.mi.cinfo=(u_long)f; // } // } #ifdef TRAFFIC printf("[%d] ", msg.cmd); fflush(stdout); for (ii = 0; ii < NR_syscalls / 32; ii++) printf("%.8x ", msg.u.r_pact.proc.mp.med_syscall[ii]); puts(""); #endif mod = &modules; while (mod != NULL) { if ((res = mod->func(&msg, data_from_kernel, &ans, &data_to_kernel)) != 0) { #ifdef TRAFFIC printf(" Applied %d. Retval %d. Ans %d\n", (int) mod, res, ans.answer); for (ii = 0; ii < NR_syscalls / 32; ii++) printf("%.8x ", ans.u.a_pact.proc.mp. med_syscall[ii]); puts(""); #endif if (res < 0) ans.answer = MED_ERR; break; } mod = mod->next; } if (mod == NULL) { #ifdef TRAFFIC printf("no module found.\n"); #endif ans.answer = MED_ERR; } if (ans.answer != MED_ERR && data_to_kernel != NULL) ans.data_len = strlen(data_to_kernel) + 1; else ans.data_len = 0; res = write(medfd, &ans, sizeof(ans)); if (res < 0) { fprintf(stderr, "%s: Write error: system error code %i: terminating...\n", me, res); close(medfd); return -1; } if (res != sizeof(ans)) { fprintf(stderr, "%s: Write error: incorrect packet length: terminating...\n", me); close(medfd); return -1; } if (ans.answer != MED_ERR && data_to_kernel != NULL) { res = write(medfd, data_to_kernel, ans.data_len); if (res < 0) { fprintf(stderr, "%s: Data write error: system error code %i: terminating...\n", me, res); close(medfd); return -1; } if (res != ans.data_len) { fprintf(stderr, "%s: Data write error: incorrect data length: terminating...\n", me); close(medfd); return -1; } } } close(medfd); return 0; }