static int mmio_write_x(int argc, const char *argv[], const struct cmd_info *info) { int ret; unsigned long ldata; data_store data; struct mmap_info mmap_addr; mmap_addr.addr = strtoull(argv[1], NULL, 0); ldata = strtoul(argv[2], NULL, 0); if (open_mapping(&mmap_addr, O_RDWR, sizeof(data)) < 0) { return -1; } ret = 0; #define DO_WRITE(mem_, off_, size_)\ data.u ##size_ = (typeof(data.u ##size_))ldata;\ *(typeof(data.u ##size_) *)(mem_+off_) = data.u ##size_ switch (get_command_size(info)) { case SIZE8: DO_WRITE(mmap_addr.mem, mmap_addr.off, 8); break; case SIZE16: DO_WRITE(mmap_addr.mem, mmap_addr.off, 16); break; case SIZE32: DO_WRITE(mmap_addr.mem, mmap_addr.off, 32); break; case SIZE64: if (sizeof(void *) != sizeof(uint64_t)) { fprintf(stderr, "warning: 64 bit operations might " "not be atomic on 32 bit builds\n"); } DO_WRITE(mmap_addr.mem, mmap_addr.off, 64); break; default: fprintf(stderr, "invalid mmio_write parameter\n"); ret = -1; } close_mapping(&mmap_addr); return ret; }
char* send_command(const char* command, const char* argument) { open_socket(); #define DO_WRITE(buf) \ if (write(sockfd, buf, strlen(buf)) != strlen(buf)) { \ perror("write error to pathname translation server"); \ abort(); \ } DO_WRITE(command); DO_WRITE(" "); DO_WRITE(argument); DO_WRITE("\n"); /* xxx read must be much better, we can't assume to receive the whole * answer in one read() */ { size_t buflen = 2*PATH_MAX; /* there be buffer overflows */ char* reply = calloc(1, buflen); int read_len = read(sockfd, reply, buflen); char* lf = strchr(reply, '\n'); if (!lf) { fprintf(stderr, "received incomplete reply [%s] from pathname " "translation server\n"); abort(); } *lf = 0; return reply; } }
static struct KeywordList * getKeywords(struct EXTRACT_Process * eproc, const char * filename) { struct KeywordList * pos; struct KeywordList * next; struct KeywordList * head; unsigned int count; size_t slen; int status; if (eproc->pid == -1) if (0 != do_fork(eproc)) return NULL; if (eproc->pid == -1) return NULL; fprintf(stderr, "Processing file %s\n", filename); head = NULL; pos = NULL; next = NULL; DO_WRITE(eproc->send_pipe, filename, strlen(filename)+1); DO_READ(eproc->read_pipe, &count, sizeof(unsigned int)); while (count-- > 0) { next = malloc(sizeof(struct KeywordList)); DO_READ(eproc->read_pipe, &next->keywordType, sizeof(enum EXTRACTOR_MetaType)); DO_READ(eproc->read_pipe, &slen, sizeof(size_t)); if (slen == 0) { free(next); next = NULL; continue; } if (slen > MAX_SLEN) goto ERROR; /* too large! something must have gone wrong! */ if (pos == NULL) { pos = next; next = NULL; head = pos; } else { pos->next = next; next = NULL; pos = pos->next; } pos->next = NULL; pos->keyword = malloc(slen + 1); pos->keyword[slen] = '\0'; DO_READ(eproc->read_pipe, pos->keyword, slen); } return head; ERROR: #if DEBUG_IPC fprintf(stderr, "READ ERROR!\n"); #endif if (next != NULL) free(next); freeKeywords(head); if (eproc->send_pipe != -1) close(eproc->send_pipe); eproc->send_pipe = -1; if (eproc->read_pipe != -1) close(eproc->read_pipe); eproc->read_pipe = -1; if (eproc->pid != -1) { kill(eproc->pid, SIGTERM); waitpid(eproc->pid, &status, 0); } eproc->pid = -1; return NULL; }
/** * @return 0 on success, 1 on error. */ static int do_fork(struct EXTRACT_Process * proc) { int filedes1[2]; int filedes2[2]; char buffer[FILENAME_MAX+2]; size_t pos; ssize_t ret; size_t slen; struct EXTRACTOR_PluginList * list; char * filename; struct AccuCtx acc_ctx; #if DEBUG_IPC fprintf(stderr, "Forking!\n"); #endif if (0 != pipe(filedes1)) { proc->my_log(proc->log_ctx, DOODLE_LOG_CRITICAL, _("Call to '%s' failed: %s\n"), "pipe", strerror(errno)); return 1; } if (0 != pipe(filedes2)) { proc->my_log(proc->log_ctx, DOODLE_LOG_CRITICAL, _("Call to '%s' failed: %s\n"), "pipe", strerror(errno)); close(filedes1[0]); close(filedes1[1]); return 1; } /* log before fork, just to avoid out-of-process problems with my_log */ if (proc->do_default) proc->my_log(proc->log_ctx, DOODLE_LOG_VERY_VERBOSE, (_("Loading default set of libextractor plugins.\n"))); if (proc->libs != NULL) proc->my_log(proc->log_ctx, DOODLE_LOG_VERY_VERBOSE, _("Loading libextractor plugins: '%s'\n"), proc->libs); proc->pid = fork(); if (proc->pid == -1) { proc->my_log(proc->log_ctx, DOODLE_LOG_CRITICAL, _("Call to '%s' failed: %s\n"), "fork", strerror(errno)); close(filedes1[0]); close(filedes1[1]); close(filedes2[0]); close(filedes2[1]); return 1; } if (proc->pid != 0) { close(filedes1[1]); close(filedes2[0]); proc->send_pipe = filedes2[1]; proc->read_pipe = filedes1[0]; return 0; } /* we're now in the forked process! */ close(filedes1[0]); close(filedes2[1]); list = NULL; if (proc->do_default) list = EXTRACTOR_plugin_add_defaults(EXTRACTOR_OPTION_DEFAULT_POLICY); if (proc->libs != NULL) list = EXTRACTOR_plugin_add_config(list, proc->libs, EXTRACTOR_OPTION_DEFAULT_POLICY); pos = 0; buffer[FILENAME_MAX + 1] = '\0'; ret = read(filedes2[0], &buffer[pos], FILENAME_MAX + 1 - pos); while ( (-1 != ret) && (ret != 0) ) { pos += ret; slen = strlen(buffer) + 1; if (slen <= pos) { filename = strdup(buffer); memmove(buffer, &buffer[slen], pos - slen); pos = pos - slen; acc_ctx.count = 0; acc_ctx.size = 0; acc_ctx.keywords = NULL; acc_ctx.types = NULL; EXTRACTOR_extract(list, filename, NULL, 0, &accumulator, &acc_ctx); DO_WRITE(filedes1[1], &acc_ctx.count, sizeof(unsigned int)); while (0 != acc_ctx.count--) { DO_WRITE(filedes1[1], &acc_ctx.types[acc_ctx.count], sizeof(enum EXTRACTOR_MetaType)); slen = strlen(acc_ctx.keywords[acc_ctx.count]); if (slen > MAX_SLEN) slen = MAX_SLEN; /* cut off -- far too large! */ DO_WRITE(filedes1[1], &slen, sizeof(size_t)); DO_WRITE(filedes1[1], acc_ctx.keywords[acc_ctx.count], slen); free(acc_ctx.keywords[acc_ctx.count]); } free (acc_ctx.keywords); free (acc_ctx.types); acc_ctx.keywords = NULL; acc_ctx.types = NULL; acc_ctx.size = 0; } ret = read(filedes2[0], &buffer[pos], FILENAME_MAX + 1 - pos); } /* exit / cleanup */ ERROR: free (acc_ctx.keywords); free (acc_ctx.types); EXTRACTOR_plugin_remove_all (list); close(filedes2[0]); close(filedes1[1]); /* never return - we were forked! */ exit(0); return 1; /* eh, dead */ }
int main (int argc, char *argv[], char *environ[]) { int n = 1; int valid = -1; char iobuf[BUFSIZ]; char sysconfdir[BUFSIZ]; char c_str[BUFSIZ]; char c_command[BUFSIZ]; char *p = NULL; char *rand = rand2str (16); time_t now = time ((time_t *) NULL); struct stat s; struct sigaction saterm; struct sigaction sawinch; struct sigaction sachild; struct timeval tv; double oldtime, newtime; struct stat ttybuf; int c; char argtest[BUFSIZ]; user.vshell = NULL; user.shell.ptr = NULL; user.home.ptr = NULL; user.term.ptr = NULL; progname = argv[0]; if ((p = (char *) strrchr (progname, '/')) != NULL) progname = p + 1; if (*progname == '-') loginshell = 1; /* Who are you? */ user.pw = getpwuid ((uid_t) getuid ()); if (user.pw == NULL) { fprintf (stderr, "I do not know who you are. Stopping.\n"); perror ("getpwuid"); exit (EXIT_FAILURE); } strncpy (user.to, user.pw->pw_name, BUFSIZ - 1); user.term.ptr = getenv ("TERM"); if (user.term.ptr == NULL) user.term.ptr = "dumb"; if (strlen (user.term.ptr) < 1) user.term.ptr = "dumb"; snprintf (sysconfdir, BUFSIZ - 1, "%s/sudosh.conf", SYSCONFDIR); parse (&sudosh_option, sysconfdir); while ((c = getopt (argc, argv, "c:hivV")) != EOF) { switch (c) { case 'c': // fprintf(stderr,"optarg is [%s]\n",optarg); strncpy (user.from, user.pw->pw_name, BUFSIZ - 1); strncpy (c_str, optarg, BUFSIZ - 1); strncpy (c_command, optarg, BUFSIZ - 1); p = strchr (c_str, ' '); if (p) { p[0] = 0; // fprintf(stderr,"args=%s\n",c_args); } if (c_str[0] != 0) { // Test for methods of escape if (strchr (c_command, ';') != NULL || strchr (c_command, '&') != NULL || strchr (c_command, '|') != NULL || strchr (c_command, '<') != NULL || strchr (c_command, '>') != NULL || strchr (c_command, '`') != NULL) { fprintf (stderr, "\"%s\" isn't allowed to be executed with process or redirect controls.\n", c_command); exit (EXIT_FAILURE); } // fprintf(stderr,"Testing c\n"); // Make sure that c_str is in argallow sprintf (argtest, "$%.100s$", c_str); // fprintf(stderr,"Testing for %s\n",argtest); if (strstr (sudosh_option.argallow, argtest) != NULL || strchr(sudosh_option.argallow, '*')!=NULL) { FILE *f; snprintf (script.name, (size_t) BUFSIZ - 1, "%s/%s%c%s%cinteractive%c%i%c%s", sudosh_option.logdir, user.from, sudosh_option.fdl, user.to, sudosh_option.fdl, sudosh_option.fdl, (int) now, sudosh_option.fdl, rand); f = fopen (script.name, "w"); if (f == (FILE *) 0) { fprintf (stderr, "%.100s: %.100s (%i)\n", script.name, strerror (errno), errno); exit (EXIT_FAILURE); } fprintf (f, "%.256s\n", c_str); fclose (f); execl ("/bin/sh", "sh", "-c", c_command, (char *) 0); exit (EXIT_SUCCESS); break; } else { fprintf (stderr, "\"%s\" isn't allowed to be executed.\n", c_str); exit (EXIT_FAILURE); break; } } break; case 'h': case '?': fprintf (stdout, "Usage: sudosh\n" "sudo shell that supports input and output logging to syslog\n" "\n" "-h, --help display this help and exit\n" "-i, --init initialize logdir (mkdir and chmod) (ignored for compatibility)\n" "-v, --version output version information and exit\n" "\n" "Report bugs to <%s>\n", PACKAGE_BUGREPORT); exit (EXIT_SUCCESS); break; case 'i': fprintf (stdout, "Ignoring initialize option, this is done automatically\n"); exit (EXIT_SUCCESS); break; case 'v': case 'V': fprintf (stdout, "%s version %s\n", PACKAGE_NAME, VERSION); exit (EXIT_SUCCESS); break; default: fputs ("Try `sudosh -h' for more information.\n", stderr); exit (EXIT_FAILURE); break; } } if (ttyname (0) != NULL) { if (stat (ttyname (0), &ttybuf) == 0) { if ((getpwuid (ttybuf.st_uid)->pw_name) == NULL) { fprintf (stderr, "I have no idea who you are.\n"); exit (EXIT_FAILURE); } strncpy (user.from, getpwuid (ttybuf.st_uid)->pw_name, BUFSIZ - 1); } else { fprintf (stderr, "Couldn't stat %s\n", ttyname (0)); exit (EXIT_FAILURE); } } else { fprintf (stderr, "%s: couldn't get your controlling terminal.\n", progname); exit (EXIT_FAILURE); } user.pw = getpwuid ((uid_t) getuid ()); snprintf (user.home.str, BUFSIZ - 1, "HOME=%s", user.pw->pw_dir); strncpy (user.to_home.str, user.pw->pw_dir, BUFSIZ - 1); snprintf (user.term.str, BUFSIZ - 1, "TERM=%s", user.term.ptr); #ifdef HAVE_GETUSERSHELL if ((user.shell.ptr = getenv ("SHELL")) == NULL) user.shell.ptr = user.pw->pw_shell; /* check against /etc/shells to make sure it's a real shell */ setusershell (); while ((user.vshell = (char *) getusershell ()) != (char *) 0) { if (strcmp (user.shell.ptr, user.vshell) == 0) valid = 1; } endusershell (); if (valid != 1) { if (user.shell.ptr == NULL) { fprintf (stderr, "Could not determine a valid shell.\n"); if (sudosh_option.priority != -1) mysyslog (sudosh_option.priority, "Could not determine a valid shell"); exit (EXIT_FAILURE); } else { fprintf (stderr, "%s is not in /etc/shells\n", user.shell.ptr); mysyslog (sudosh_option.priority, "%s,%s: %s is not in /etc/shells", user.from, ttyname (0), user.shell.ptr); exit (EXIT_FAILURE); } } if (stat ((const char *) user.shell.ptr, &s) == -1) { fprintf (stderr, "Shell %s doesn't exist.\n", user.shell.ptr); if (sudosh_option.priority != -1) mysyslog (sudosh_option.priority, "%s,%s: shell %s doesn't exist.", user.from, ttyname (0), user.shell.ptr); exit (EXIT_FAILURE); } #else user.shell.ptr = user.pw->pw_shell; #endif /* HAVE_GETUSERSHELL */ if (loginshell) user.shell.ptr = sudosh_option.defshell; snprintf (script.name, (size_t) BUFSIZ - 1, "%s/%s%c%s%cscript%c%i%c%s", sudosh_option.logdir, user.from, sudosh_option.fdl, user.to, sudosh_option.fdl, sudosh_option.fdl, (int) now, sudosh_option.fdl, rand); snprintf (timing.name, (size_t) BUFSIZ - 1, "%s/%s%c%s%ctime%c%i%c%s", sudosh_option.logdir, user.from, sudosh_option.fdl, user.to, sudosh_option.fdl, sudosh_option.fdl, (int) now, sudosh_option.fdl, rand); #ifdef RECORDINPUT snprintf (input.name, (size_t) BUFSIZ - 1, "%s/%s%c%s%cinput%c%i%c%s", sudosh_option.logdir, user.from, sudosh_option.fdl, user.to, sudosh_option.fdl, sudosh_option.fdl, (int) now, sudosh_option.fdl, rand); #endif snprintf (start_msg, BUFSIZ - 1, "starting session for %s as %s, tty %s, shell %s", user.from, user.to, ttyname (0), user.shell.ptr); set_perms_and_open_file(&script); set_perms_and_open_file(&timing); #ifdef RECORDINPUT set_perms_and_open_file(&input); #endif if (sudosh_option.priority != -1) mysyslog (sudosh_option.priority, start_msg); rawmode (0); if (findms (&pspair) < 0) { perror ("open pty failed"); bye (EXIT_FAILURE); } switch (fork ()) { case 0: close (pspair.mfd); prepchild (&pspair); case -1: perror ("fork failed"); bye (EXIT_FAILURE); default: close (pspair.sfd); } orig_euid = geteuid(); if (seteuid (getuid ()) != 0) { perror ("setuid failed"); bye (EXIT_FAILURE); } memset (&sawinch, 0, sizeof sawinch); sawinch.sa_handler = newwinsize; sawinch.sa_flags = SA_RESTART; sigaction (SIGWINCH, &sawinch, (struct sigaction *) 0); memset (&saterm, 0, sizeof saterm); saterm.sa_handler = bye; sigaction (SIGTERM, &sawinch, (struct sigaction *) 0); memset (&sachild, 0, sizeof sachild); sachild.sa_handler = bye; sigaction (SIGCHLD, &sachild, (struct sigaction *) 0); oldtime = time (NULL); while (n > 0) { fd_set readfds; FD_ZERO (&readfds); FD_SET (pspair.mfd, &readfds); FD_SET (0, &readfds); gettimeofday ((struct timeval *) &tv, NULL); if (select (pspair.mfd + 1, &readfds, (fd_set *) 0, (fd_set *) 0, (struct timeval *) 0) < 0) { if (errno == EINTR) continue; perror ("select"); bye (EXIT_FAILURE); } if (FD_ISSET (pspair.mfd, &readfds)) { if ((n = read (pspair.mfd, iobuf, sizeof (iobuf))) > 0) { DO_WRITE (1, iobuf, n); script.bytes += DO_WRITE (script.fd, iobuf, n); } newtime = tv.tv_sec + (double) tv.tv_usec / 1000000; snprintf (timing.str, BUFSIZ - 1, "%f %i\n", newtime - oldtime, n); timing.bytes += DO_WRITE (timing.fd, &timing.str, strlen (timing.str)); oldtime = newtime; } if (FD_ISSET (0, &readfds)) { if ((n = read (0, iobuf, BUFSIZ)) > 0) { DO_WRITE (pspair.mfd, iobuf, n); #ifdef RECORDINPUT switch (*iobuf) { case '\r': snprintf (input.str, BUFSIZ - 1, "\n"); break; case 0x003: snprintf (input.str, BUFSIZ - 1, "(CTRL-C)"); break; case 0x004: snprintf (input.str, BUFSIZ - 1, "(CTRL-D)\n"); break; case 0x1a: snprintf (input.str, BUFSIZ - 1, "(CTRL-Z)\n"); break; case 0x1b: snprintf (input.str, BUFSIZ - 1, "(ESC)"); break; default: DO_WRITE (input.fd, iobuf, 1); written = 1; break; } if (written == 0) { DO_WRITE (input.fd, &input.str, strlen (input.str)); } #endif } } } bye (EXIT_SUCCESS); return (0); }