/* * create pty pair and fork using my_pty_fork; parent returns immediately; child * executes the part of rlwrap's command line that remains after * read_options_and_command_name() has harvested rlwrap's own options */ static void fork_child(char *command_name, char **argv) { char *arg = argv[optind], *p, **argp; int pid; command_line = mysavestring(arg); for (argp = argv + optind + 1; *argp; argp++) { command_line = append_and_free_old (command_line, " "); command_line = append_and_free_old (command_line, *argp); } pid = my_pty_fork(&master_pty_fd, &saved_terminal_settings, &winsize); if (pid > 0) /* parent: */ return; else { /* child: */ DPRINTF1(DEBUG_TERMIO, "preparing to execute %s", arg); close_open_files_without_writing_buffers(); if (client_term_name) mysetenv("TERM", client_term_name); if (execvp(argv[optind], &argv[optind]) < 0) { if (last_opt > 0 && last_option_didnt_have_optional_argument) { /* e.g. 'rlwrap -a Password: sqlpus' will try to exec 'Password:'******'; !(){}"; *p; p++) /* does arg need shell quoting? */ if (strchr(arg,*p)) { arg = add3strings("'", arg,"'"); /* quote it */ break; } fprintf(stderr, "Did you mean '%s' to be an option argument?\nThen you should write -%c%s, without the space(s)\n", argv[optind], last_opt, arg); } myerror("Cannot execute %s", argv[optind]); /* stillborn child, parent will live on and display child's last gasps */ } } }
void man_getopt (int argc, char **argv) { char *config_file = NULL; char *manp = NULL; int optct = 0; optct = get_options_from_argvec(argc, argv, &config_file, &manp); read_config_file (config_file); /* If no options were given and MANDEFOPTIONS is set, use that */ if (optct == 0) { const char *defopts = getval ("MANDEFOPTIONS"); get_options_from_string(defopts); } /* In case an explicit -P option was given, put it in the environment for possible use with -k or -K. Ignore errors (out of memory?) */ if (pager && (global_apropos || apropos || whatis)) mysetenv("PAGER", pager); if (pager == NULL || *pager == '\0') if ((pager = getenv ("MANPAGER")) == NULL) if ((pager = getenv ("PAGER")) == NULL) pager = getval ("PAGER"); if (debug) gripe (PAGER_IS, pager); /* Ditto for BROWSER and -B */ if (browser && (global_apropos || apropos || whatis)) mysetenv("BROWSER", browser); if (browser == NULL || *browser == '\0') if ((browser = getenv ("BROWSER")) == NULL) browser = getval ("BROWSER"); if (debug) gripe (BROWSER_IS, browser); /* Ditto for HTMLHTMLPAGER and -D */ if (htmlpager && (global_apropos || apropos || whatis)) mysetenv("HTMLPAGER", htmlpager); if (htmlpager == NULL || *htmlpager == '\0') if ((htmlpager = getenv ("HTMLPAGER")) == NULL) htmlpager = getval ("HTMLPAGER"); if (debug) gripe (HTMLPAGER_IS, htmlpager); if (do_compress && !*getval ("COMPRESS")) { if (debug) gripe (NO_COMPRESS); do_compress = 0; } if (do_troff && !*getval ("TROFF")) { gripe (NO_TROFF, configuration_file); exit (1); } opt_manpath = manp; /* do not yet expand manpath - maybe it is not needed */ if (alt_system_name == NULL || *alt_system_name == '\0') if ((alt_system_name = getenv ("SYSTEM")) != NULL) alt_system_name = my_strdup (alt_system_name); }
int dgl_exec_cmdqueue(struct dg_cmdpart *queue, int game, struct dg_user *me) { int i; struct dg_cmdpart *tmp = queue; char *p1; char *p2; int played = 0; if (!queue) return 1; p1 = (char *)malloc(1024); p2 = (char *)malloc(1024); if (!p1 || !p2) return 1; return_from_submenu = 0; while (tmp && !return_from_submenu) { if (tmp->param1) strcpy(p1, dgl_format_str(game, me, tmp->param1, NULL)); if (tmp->param2) strcpy(p2, dgl_format_str(game, me, tmp->param2, NULL)); switch (tmp->cmd) { default: break; case DGLCMD_RAWPRINT: if (p1) fprintf(stdout, "%s", p1); break; case DGLCMD_MKDIR: if (p1 && (access(p1, F_OK) != 0)) mkdir(p1, 0755); break; case DGLCMD_UNLINK: if (p1 && (access(p1, F_OK) == 0)) unlink(p1); break; case DGLCMD_CHDIR: if (p1) { if (chdir(p1) == -1) { debug_write("chdir-command failed"); graceful_exit(123); } } break; case DGLCMD_IF_NX_CP: if (p1 && p2) { FILE *tmpfile; tmpfile = fopen(p2, "r"); if (tmpfile) { fclose(tmpfile); break; } } /* else fall through to cp */ case DGLCMD_CP: if (p1 && p2) { FILE *cannedf, *newfile; char buf[1024]; size_t bytes; /* FIXME: use nethack-themed error messages here, as per write_canned_rcfile() */ if (!(cannedf = fopen (p1, "r"))) break; if (!(newfile = fopen (p2, "w"))) break; while ((bytes = fread (buf, 1, 1024, cannedf)) > 0) { if (fwrite (buf, 1, bytes, newfile) != bytes) { if (ferror (newfile)) { fclose (cannedf); fclose (newfile); break; } } } fclose (cannedf); fclose (newfile); chmod (p2, default_fmode); } break; case DGLCMD_EXEC: if (p1 && p2) { pid_t child; char *myargv[3]; myargv[0] = p1; myargv[1] = p2; myargv[2] = 0; clear(); refresh(); endwin(); idle_alarm_set_enabled(0); child = fork(); if (child == -1) { perror("fork"); debug_write("exec-command fork failed"); graceful_exit(114); } else if (child == 0) { execvp(p1, myargv); exit(0); } else waitpid(child, NULL, 0); idle_alarm_set_enabled(1); initcurses(); check_retard(1); } break; case DGLCMD_SETENV: if (p1 && p2) mysetenv(p1, p2, 1); break; case DGLCMD_CHPASSWD: if (loggedin) changepw(1); break; case DGLCMD_CHMAIL: if (loggedin) change_email(); break; case DGLCMD_WATCH_MENU: inprogressmenu(-1); break; case DGLCMD_LOGIN: if (!loggedin) loginprompt(0); if (loggedin) runmenuloop(dgl_find_menu(get_mainmenu_name())); break; case DGLCMD_REGISTER: if (!loggedin && globalconfig.allow_registration) newuser(); break; case DGLCMD_QUIT: debug_write("command: quit"); graceful_exit(0); /* break; */ case DGLCMD_SUBMENU: if (p1) runmenuloop(dgl_find_menu(p1)); break; case DGLCMD_RETURN: return_from_submenu = 1; break; case DGLCMD_PLAY_IF_EXIST: if (!(loggedin && me && p1 && p2)) break; { FILE *tmpfile; tmpfile = fopen(p2, "r"); if (tmpfile) { fclose(tmpfile); } else break; } /* else fall through to playgame */ case DGLCMD_PLAYGAME: if (loggedin && me && p1 && !played) { int userchoice, i; char *tmpstr; for (userchoice = 0; userchoice < num_games; userchoice++) { if (!strcmp(myconfig[userchoice]->game_id, p1) || !strcmp(myconfig[userchoice]->game_name, p1) || !strcmp(myconfig[userchoice]->shortname, p1)) { if (purge_stale_locks(userchoice)) { if (myconfig[userchoice]->rcfile) { if (access (dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt, NULL), R_OK) == -1) write_canned_rcfile (userchoice, dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt, NULL)); } setproctitle("%s [playing %s]", me->username, myconfig[userchoice]->shortname); clear(); refresh(); endwin (); /* first run the generic "do these when a game is started" commands */ dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_GAMESTART], userchoice, me); /* then run the game-specific commands */ dgl_exec_cmdqueue(myconfig[userchoice]->cmdqueue, userchoice, me); /* fix the variables in the arguments */ for (i = 0; i < myconfig[userchoice]->num_args; i++) { tmpstr = strdup(dgl_format_str(userchoice, me, myconfig[userchoice]->bin_args[i], NULL)); free(myconfig[userchoice]->bin_args[i]); myconfig[userchoice]->bin_args[i] = tmpstr; } signal(SIGWINCH, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); idle_alarm_set_enabled(0); /* launch program */ ttyrec_main (userchoice, me->username, dgl_format_str(userchoice, me, myconfig[userchoice]->ttyrecdir, NULL), gen_ttyrec_filename()); idle_alarm_set_enabled(1); played = 1; /* lastly, run the generic "do these when a game is left" commands */ signal (SIGHUP, catch_sighup); signal (SIGINT, catch_sighup); signal (SIGQUIT, catch_sighup); signal (SIGTERM, catch_sighup); signal(SIGWINCH, sigwinch_func); dgl_exec_cmdqueue(myconfig[userchoice]->postcmdqueue, userchoice, me); dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_GAMEEND], userchoice, me); setproctitle ("%s", me->username); initcurses (); check_retard(1); /* reset retard counter */ } break; } } } break; } tmp = tmp->next; } free(p1); free(p2); return 0; }
void spawn_filter(const char *filter_command) { int input_pipe_fds[2]; int output_pipe_fds[2]; mypipe(input_pipe_fds); filter_input_fd = input_pipe_fds[1]; /* rlwrap writes filter input to this */ mypipe(output_pipe_fds); filter_output_fd = output_pipe_fds[0]; /* rlwrap reads filter output from here */ DPRINTF1(DEBUG_FILTERING, "preparing to spawn filter <%s>", filter_command); assert(!command_pid || signal_handlers_were_installed); /* if there is a command, then signal handlers are installed */ if ((filter_pid = fork()) < 0) myerror(FATAL|USE_ERRNO, "Cannot spawn filter '%s'", filter_command); else if (filter_pid == 0) { /* child */ int signals_to_allow[] = {SIGPIPE, SIGCHLD, SIGALRM, SIGUSR1, SIGUSR2}; char **argv; unblock_signals(signals_to_allow); /* when we run a pager from a filter we want to catch these */ DEBUG_RANDOM_SLEEP; i_am_child = TRUE; /* set environment for filter (it needs to know at least the file descriptors for its input and output) */ if (!getenv("RLWRAP_FILTERDIR")) mysetenv("RLWRAP_FILTERDIR", add2strings(DATADIR,"/rlwrap/filters")); mysetenv("PATH", add3strings(getenv("RLWRAP_FILTERDIR"),":",getenv("PATH"))); mysetenv("RLWRAP_VERSION", VERSION); mysetenv("RLWRAP_COMMAND_PID", as_string(command_pid)); mysetenv("RLWRAP_COMMAND_LINE", command_line); if (impatient_prompt) mysetenv("RLWRAP_IMPATIENT", "1"); mysetenv("RLWRAP_INPUT_PIPE_FD", as_string(input_pipe_fds[0])); mysetenv("RLWRAP_OUTPUT_PIPE_FD", as_string(output_pipe_fds[1])); mysetenv("RLWRAP_MASTER_PTY_FD", as_string(master_pty_fd)); close(filter_input_fd); close(filter_output_fd); if (scan_metacharacters(filter_command, "'|\"><")) { /* if filter_command contains shell metacharacters, let the shell unglue them */ char *exec_command = add3strings("exec", " ", filter_command); argv = list4("sh", "-c", exec_command, NULL); } else { /* if not, split and feed to execvp directly (cheaper, better error message) */ argv = split_with(filter_command, " "); } assert(argv[0]); if(execvp(argv[0], argv) < 0) { char *sorry = add3strings("Cannot exec filter '", argv[0], add2strings("': ", strerror(errno))); write_message(output_pipe_fds[1], TAG_ERROR, sorry, "to stdout"); /* this will kill rlwrap */ mymicrosleep(100 * 1000); /* 100 sec for rlwrap to go away should be enough */ exit (-1); } assert(!"not reached"); } else { DEBUG_RANDOM_SLEEP; signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE - we have othere ways to deal with filter death */ DPRINTF1(DEBUG_FILTERING, "spawned filter with pid %d", filter_pid); close (input_pipe_fds[0]); close (output_pipe_fds[1]); } }
static void update_shelf_path(String dirname) { mysetenv("CURSHELF", dirname, True); }
static void update_cur_path(String dirname) { strcpy(save_cur_path, dirname); mysetenv("CURDIR", dirname, True); }
int process_ssh_request(char *request) { char **av, **tmp_av, **tenv; char *flat_request,*tmpstring, *tmprequest; char bad_winscp3str[] = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server exec sftp-server"; int retval; int reqlen=strlen(request); char **env = NULL; debug(LOG_DEBUG, "processing request: \"%s\"\n", request); tmprequest=strdup(request); #ifdef WINSCP_COMPAT bad_winscp3str[57]=10; bad_winscp3str[127]=10; if(strcmp(request,bad_winscp3str)==0) { /* * switch out the command to use, winscp wont know the difference */ free(tmprequest); tmprequest=strdup(PROG_SFTP_SERVER); syslog(LOG_DEBUG, "winscp3 compat correcting to: \"[%s]\"\n", PROG_SFTP_SERVER); } #endif #ifdef GFTP_COMPAT /* * gFTP compatibility hack */ if (NULL != (tmpstring=strbeg(request, "echo -n xsftp ; "))) { free(tmprequest); tmprequest=strdup(tmpstring); printf("xsftp"); fflush(stdout); } #endif #ifdef RESTRICTIVE_FILENAMES /* * we flat out reject special chars */ if (!valid_chars(tmprequest)) { debug(LOG_DEBUG, "rejected because of invalid chars (%s)", logstamp()); free(tmprequest); return(-1); } #endif #ifdef WINSCP_COMPAT if (strbeg(tmprequest,PROG_CD)) { char *destdir=(char *)malloc(reqlen); if (destdir == NULL) { perror("malloc"); exit(EXIT_FAILURE); } /* * well, now that scponly is a persistent shell * i have to maintain a $PWD. damn. * we're going to INSIST upon a double quote * encapsulated new directory to change to. */ if ((tmprequest[(reqlen-1)]=='"') && (tmprequest[3]=='"')) { bzero(destdir,reqlen); strncpy(destdir,&tmprequest[4],reqlen-5); debug(LOG_INFO, "chdir: %s (%s)", tmprequest, logstamp()); retval=chdir(destdir); free(destdir); free(tmprequest); return(retval); } syslog(LOG_ERR, "bogus chdir request: %s (%s)", tmprequest, logstamp()); free(tmprequest); return(-1); } #endif /* * convert request string to an arg_vector */ av = build_arg_vector(tmprequest); /* * clean any path info from request and substitute our known pathnames */ av[0] = substitute_known_path(av[0]); /* * we only process wildcards for scp commands */ #ifdef ENABLE_WILDCARDS #ifdef ENABLE_SCP2 if (exact_match(av[0],PROG_SCP)) av = expand_wildcards(av); #endif #endif /* * check for a compile time chdir configuration */ #ifdef ENABLE_DEFAULT_CHDIR if (exact_match(av[0],PROG_SFTP_SERVER)) { syslog(LOG_INFO, "changing initial directory to %s", DEFAULT_CHDIR); chdir(DEFAULT_CHDIR); } #endif flat_request = flatten_vector(av); /* * Use a temp arg vector since getopt will permute the command line arguments * for anything that it does not know about. If all rsync options are well * defined this isn't necessary. */ tmp_av = build_arg_vector(flat_request); if(check_dangerous_args(tmp_av)) { syslog(LOG_ERR, "requested command (%s) tried to use disallowed argument (%s))", flat_request, logstamp()); exit(EXIT_FAILURE); } discard_vector(tmp_av); if (valid_arg_vector(av)) { /* * Unison needs the HOME environment variable be set to the directory * where the .unison directory resides. */ #ifdef USE_SAFE_ENVIRONMENT safeenv[0] = NULL; filter_allowed_env_vars(); tenv = safeenv; if (debuglevel) { while (NULL != *tenv) { syslog(LOG_DEBUG, "Environment contains \"%s\"", *tenv++); } } env = safeenv; #endif #ifdef UNISON_COMPAT /* the HOME environment variable should have been set above, but I need to make sure * that it's value as read from the environment is replaced with the actual value * as it exists within the chroot, which is what the applications will expect to see. */ if (replace_env_entry("HOME",homedir) && (((strlen(homedir) + 6 ) > FILENAME_MAX) || !mysetenv("HOME",homedir))) { syslog(LOG_ERR, "could not set HOME environment variable (%s)", logstamp()); exit(EXIT_FAILURE); } debug(LOG_DEBUG, "set non-chrooted HOME environment variable to %s (%s)", homedir, logstamp()); #endif syslog(LOG_INFO, "running: %s (%s)", flat_request, logstamp()); #ifdef WINSCP_COMPAT if (winscp_mode) { int status=0; if (fork() == 0) retval=execve(av[0],av,env); else { wait(&status); fflush(stdout); fflush(stderr); discard_vector(av); #ifdef USE_SAFE_ENVIRONMENT discard_child_vectors(safeenv); #endif free(flat_request); free(tmprequest); return(WEXITSTATUS(status)); } } else #endif { debug(LOG_DEBUG, "about to exec \"%s\" (%s)", av[0], logstamp()); retval=execve(av[0],av,env); } syslog(LOG_ERR, "failed: %s with error %s(%u) (%s)", flat_request, strerror(errno), errno, logstamp()); free(flat_request); discard_vector(av); #ifdef USE_SAFE_ENVIRONMENT discard_child_vectors(safeenv); #endif #ifdef WINSCP_COMPAT if (winscp_mode) { free(tmprequest); return(-1); } else #endif exit(errno); } /* * reaching this point in the code means the request isnt one of * our accepted commands */ if (debuglevel) { if (exact_match(flat_request,tmprequest)) syslog (LOG_ERR, "denied request: %s [%s]", tmprequest, logstamp()); else syslog (LOG_ERR, "denied request: %s (resolved to: %s) [%s]", tmprequest, flat_request, logstamp()); } free(flat_request); #ifdef WINSCP_COMPAT if (winscp_mode) { printf ("command not permitted by scponly\n"); free(tmprequest); return(-1); } else #endif exit(EXIT_FAILURE); }
int main(int argc, char **argv) { const char *user; const char *logname; const struct passwd *pw; char **newargv; //char envsh[BUFSIZ]; //char envhome[BUFSIZ]; int j; //char *neweviron[10]; char *shell; char *argv0; char *newargv0; #ifdef DEBUG_PRINTS fp = fopen("/var/log/chrootshell.log", "a"); #endif user = getenv("USER"); if (!user) die("USER not set?!"); logname = getenv("LOGNAME"); if (logname && *logname && strcmp(user, logname)) die("USER does not match LOGNAME\n"); /* Look up user in outer /etc/passwd */ pw = getpwnam(user); if (!pw) die2("no such user %s\n", user); shell = strrchr(pw->pw_shell, '/'); if (!shell) die("shell contains no / ?"); shell++; /* skip slash */ argv0 = argv[0]; if (*argv0 == '-') { /* it's a login shell */ argv0++; /* skip dash */ } if (strcmp(shell, argv0)) { fprintf(fp, "shell '%s', argv[0] '%s'\n", shell, argv[0]); die2("%s not chrootshell\n", shell); } /* Enter jail */ if (chdir(pw->pw_dir)) die2("chdir(%s) fails", pw->pw_dir); if (chroot(pw->pw_dir)) die2("chroot(%s) fails", pw->pw_dir); /* Permanently discard root privs */ if (setuid(pw->pw_uid)) die2("setuid(%d) fails", (void *)pw->pw_uid); /* Look up user in jail's /etc/passwd */ endpwent(); pw = getpwnam(user); if (!pw) die2("no such user %s in jail\n", user); /* Go to his home directory */ if (chdir(pw->pw_dir)) die2("chdir(%s) fails", pw->pw_dir); /* Fix up the environment. * Clear the whole thing out for security reasons, and give him a minimal one. */ mysetenv("SHELL", pw->pw_shell); mysetenv("HOME", pw->pw_dir); mysetenv("PATH", "/bin:/usr/bin"); mysetenv("USER", user); /* Note: rshd does not set LOGNAME, as the user hasn't really logged in... */ if (logname && *logname) mysetenv("LOGNAME", user); myenv[myenv_used] = 0; /* yes, this is the posix way of replacing the entire environment */ environ = myenv; /* Close the handle to the jail's /etc/passwd */ endpwent(); /* Finally, run the original command. */ newargv = malloc((argc + 3) * sizeof(argv[0])); if (!newargv) die("malloc fails?!\n"); j = 0; if (argc == 1) { /* Case 1: interactive login; argv[0] is the shell, there are no args */ char *buf = malloc(strlen(pw->pw_shell) + 2); newargv0 = pw->pw_shell; sprintf(buf, "-%s", pw->pw_shell); newargv[j++] = buf; } else if (argc > 1 && !strcmp(argv[1], "-c")) { /* Case 2: non-interactive; argv[0] is the shell, argv[1] is -c, argv[2] is the command */ newargv[j++] = pw->pw_shell; newargv0 = pw->pw_shell; newargv[j++] = "-c"; newargv[j++] = argv[2]; } else die("Expected argc==1 || (argc==3 && argv[1] == '-c')"); newargv[j++] = 0; execvp(newargv0, newargv); die2("exec %s fails", newargv[0]); /*notreached*/ return 1; }