void spc_sanitize_files(void) { int standard_fds[] = { STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO }; int standard_fds_count = (int)(sizeof(standard_fds) / sizeof(standard_fds[0])); // Make sure all open descriptors other than the standard ones are closed int fds = getdtablesize(); for (int i = standard_fds_count; i < fds; ++i) close(i); // Verify that the standard descriptors are open. If they're not, attempt to // open them using /dev/null. If any are unsuccessful, abort. for (int i = 0; i < standard_fds_count; ++i) { struct stat st; int fd = standard_fds[i]; if (fstat(fd, &st) == -1 && (errno != EBADF || !open_devnull(fd))) { abort(); } } }
bool create_child(struct child_process *child) { int errsv; int child_errno = 0; int status_pipe[2]; int stdin_pipe[2]; int stdout_pipe[2]; int stderr_pipe[2]; if (pipe(status_pipe) < 0) return false; (void) fcntl(status_pipe[1], F_SETFD, FD_CLOEXEC); if (child->stdin_fd == REDIRECT_PIPE) { if (pipe(stdin_pipe) < 0) { errsv = errno; goto stdin_pipe_failed; } } if (child->stdout_fd == REDIRECT_PIPE) { if (pipe(stdout_pipe) < 0) { errsv = errno; goto stdout_pipe_failed; } } if (child->stderr_fd == REDIRECT_PIPE) { if (pipe(stderr_pipe) < 0) { errsv = errno; goto stderr_pipe_failed; } } child->pid = fork(); if (child->pid == 0) { /* Child. */ fd_set except_fds; if (child->stdin_fd == REDIRECT_PIPE) (void) dup2(stdin_pipe[0], STDIN_FILENO); else if (child->stdin_fd == REDIRECT_DEV_NULL) (void) dup2(open_devnull(), STDIN_FILENO); else if (child->stdin_fd != NO_REDIRECT) (void) dup2(child->stdin_fd, STDIN_FILENO); if (child->stdout_fd == REDIRECT_PIPE) (void) dup2(stdout_pipe[1], STDOUT_FILENO); else if (child->stdout_fd == REDIRECT_DEV_NULL) (void) dup2(open_devnull(), STDOUT_FILENO); else if (child->stdout_fd != NO_REDIRECT) (void) dup2(child->stdout_fd, STDOUT_FILENO); if (child->stderr_fd == REDIRECT_PIPE) (void) dup2(stderr_pipe[1], STDERR_FILENO); else if (child->stderr_fd == REDIRECT_DEV_NULL) (void) dup2(open_devnull(), STDERR_FILENO); else if (child->stderr_fd != NO_REDIRECT) (void) dup2(child->stderr_fd, STDERR_FILENO); FD_ZERO(&except_fds); FD_SET(STDIN_FILENO, &except_fds); FD_SET(STDOUT_FILENO, &except_fds); FD_SET(STDERR_FILENO, &except_fds); FD_SET(status_pipe[1], &except_fds); (void) close_fds(&except_fds); (void) setgid(getgid()); (void) setuid(getuid()); if (child->function != NULL) { (void) close(status_pipe[1]); _exit(child->function(child->argument)); } else { execv(child->path, (char *const*)child->argv); (void) write(status_pipe[1], &errno, sizeof errno); } _exit(1); } if (child->pid < 0) { errsv = errno; goto fork_failed; } (void) close(status_pipe[1]); /* Get the error status from the child, if any. */ if (read(status_pipe[0], &child_errno, sizeof child_errno) == sizeof child_errno) { errsv = child_errno; goto child_failed; } (void) close(status_pipe[0]); if (child->stdin_fd == REDIRECT_PIPE) { /* Write end. */ child->stdin_fd = stdin_pipe[1]; /* Read end. */ (void) close(stdin_pipe[0]); } if (child->stdout_fd == REDIRECT_PIPE) { /* Read end. */ child->stdout_fd = stdout_pipe[0]; /* Write end. */ (void) close(stdout_pipe[1]); } if (child->stderr_fd == REDIRECT_PIPE) { /* Read end. */ child->stderr_fd = stderr_pipe[0]; /* Write end. */ (void) close(stderr_pipe[1]); } return true; child_failed: fork_failed: if (child->stderr_fd == REDIRECT_PIPE) { (void) close(stderr_pipe[0]); (void) close(stderr_pipe[1]); } stderr_pipe_failed: if (child->stdout_fd == REDIRECT_PIPE) { (void) close(stdout_pipe[0]); (void) close(stdout_pipe[1]); } stdout_pipe_failed: if (child->stdin_fd == REDIRECT_PIPE) { (void) close(stdin_pipe[0]); (void) close(stdin_pipe[1]); } stdin_pipe_failed: (void) close(status_pipe[0]); (void) close(status_pipe[1]); errno = errsv; return false; }
/** * Option parsing routine. * * Remember to update other places, such as execute_rsh_multiple routine when changing here. * @return 1 on failure. * @return 0 on success. */ int parse_options ( int ac, char ** av) { int c; /* option */ linkedlist * machinelist = NULL; linkedlist * rshcommandline_r = NULL; /* command line for rsh in reverse order*/ #ifdef HAVE_GETOPT_LONG int index_point; static struct option long_options[]= { {"verbose", no_argument, 0, 'v'}, {"quiet", no_argument, 0, 'q'}, {"show-machine-names", no_argument, 0, 'M'}, {"hide-machine-names", no_argument, 0, 'H'}, {"duplicate-input", no_argument, 0, 'i'}, {"bufsize", required_argument, 0, 'b'}, /* machine-specification */ {"machine", required_argument, 0, 'm'}, {"num-topology", required_argument, 0, 'n'}, {"all", no_argument, 0, 'a' }, {"group", required_argument, 0, 'g'}, {"file", required_argument, 0, 'f'}, /* rsh/ssh specification */ {"remoteshell", required_argument, 0, 'r'}, {"remoteshellopt", required_argument, 0, 'o'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"wait-shell", no_argument, 0, 'w'}, {"concurrent-shell", no_argument, 0, 'c'}, {"forklimit", required_argument, 0, 'F'}, {0,0,0,0} }; #else #define getopt_long(a,b,c,d,e) getopt(a,b,c) #endif #ifdef GETOPT_WITH_GNU_REORDERING_EXTENTION #define EXTRAVALUE "+" /* add this to get GNU getopt to work in POSIX manner */ #else #define EXTRAVALUE #endif while((c = getopt_long (ac, av, EXTRAVALUE "vqm:ar:f:g:hVcwo:MHn:ib:F:", long_options, &index_point)) != -1) { switch (c) { case 'a': if (verbose_flag) printf (_("Adding all machines to the list\n")); { char * buf; if (asprintf(&buf, "%s/.dsh/machines.list", getenv("HOME"))<0) { fprintf (stderr, _("%s: asprintf failed\n"), PACKAGE); return 1; } machinelist = read_machinelist(machinelist, buf, DSHCONFDIR"/machines.list"); free (buf); } break; case 'g': { if ('@' == *optarg) { /* using libc call for using netgroup. */ /* +1 to skip @ */ if (verbose_flag) printf (_("Adding netgroup %s to the list\n"), optarg + 1); machinelist = read_machinenetgroup(machinelist, optarg+1); } else { /* using dsh's own method. */ char * buf1, *buf2; if (verbose_flag) printf (_("Adding group %s to the list\n"), optarg); if (asprintf(&buf1, DSHCONFDIR"/group/%s", optarg) < 0) { fprintf (stderr, _("%s: asprintf failed\n"), PACKAGE); return 1; } if (asprintf(&buf2, "%s/.dsh/group/%s", getenv("HOME"), optarg)<0) { fprintf (stderr, _("%s: asprintf failed\n"), PACKAGE); return 1; } machinelist = read_machinelist (machinelist, buf2, buf1); free(buf1);free(buf2); } } break; case 'f': if (verbose_flag) printf (_("Adding file %s to the list\n"), optarg); machinelist = read_machinelist (machinelist, optarg, NULL); break; case 'F': forklimit = atoi (optarg); wait_shell = 0; if (verbose_flag) printf (_("Setting forklimit to %i and wait_shell to %i\n"), forklimit, wait_shell); break; case 'v': if (verbose_flag) printf (_("Verbose flag on\n")); verbose_flag=1; break; case 'q': if (verbose_flag) printf (_("Verbose flag off\n")); verbose_flag=0; break; case 'M': if (verbose_flag) printf (_("Show machine names on output\n")); pipe_option |= PIPE_OPTION_OUTPUT; break; case 'H': if (verbose_flag) printf (_("Dont show machine names on output\n")); pipe_option &= ~(PIPE_OPTION_OUTPUT); break; case 'i': if (verbose_flag) printf (_("Duplicate input to all processes\n")); pipe_option |= PIPE_OPTION_INPUT; break; case 'b': if (verbose_flag) printf (_("Buffer size used for dupliation\n")); buffer_size = atoi(optarg); if (buffer_size < 1) { fprintf (stderr, _("Buffer size needs to be greater than 1\n")); return 1; } break; case 'm': if (verbose_flag) printf (_("Adding machine %s to list\n"), optarg); machinelist = split_machines_list_and_add_machines (machinelist, optarg); break; case 'n': if (verbose_flag) printf (_("Topology number set to %s\n"), optarg); num_topology = atoi (optarg); break; case 'h': print_help(); exit(1); break; case 'V': print_version(); exit(1); break; case 'r': /* specify the shell command */ if (verbose_flag) printf(_("Using %s as the remote shell\n"), optarg); remoteshell_command = strdup (optarg); break; case 'o': /* specify the shell command options */ if (verbose_flag) printf(_("Adding [%s] to shell options\n"), optarg); remoteshell_command_opt_r = lladd (remoteshell_command_opt_r, optarg); break; case 'w': /* wait shell */ if (verbose_flag) printf (_("Wait for shell to finish executing\n")); wait_shell=1; break; case 'c': /* concurrent shell */ if (verbose_flag) printf (_("Do not wait for shell to finish\n")); wait_shell=0; break; case '?': #ifndef HAVE_GETOPT_LONG /* getopt-long handles this option properly. */ if (isprint (optopt)) fprintf (stderr, _("Unkown option -%c.\n"), optopt); else fprintf (stderr, _("Unkown option character 0x%x.\n"), optopt); #endif return 1; default: if (verbose_flag) printf (_("Unhandled option\n")); break; } } if (!machinelist) { fprintf (stderr, _("%s: no machine specified\n"), PACKAGE); return 1; } { /* generate the command line for remote. */ int i; for (i=optind; i < ac; ++i) { rshcommandline_r = lladd(rshcommandline_r, av[i]); } } /* do sanity checking, and exit if it fails. */ if (sanity_checking()) return 1; if (!(pipe_option & PIPE_OPTION_INPUT)) open_devnull(); /* open /dev/null if no input pipe is required */ /* reverse the list, which is in reverse order, to make the right order */ machinelist = llreverse (machinelist); /* actually execute the code. */ return do_shell(machinelist, rshcommandline_r); }