File: | src/usr.bin/vi/build/../ex/ex_shell.c |
Warning: | line 112, column 16 Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ex_shell.c,v 1.15 2015/03/28 12:54:37 bcallah Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1992, 1993, 1994 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * Copyright (c) 1992, 1993, 1994, 1995, 1996 |
7 | * Keith Bostic. All rights reserved. |
8 | * |
9 | * See the LICENSE file for redistribution information. |
10 | */ |
11 | |
12 | #include "config.h" |
13 | |
14 | #include <sys/queue.h> |
15 | #include <sys/wait.h> |
16 | |
17 | #include <bitstring.h> |
18 | #include <ctype.h> |
19 | #include <errno(*__errno()).h> |
20 | #include <limits.h> |
21 | #include <signal.h> |
22 | #include <stdio.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <unistd.h> |
26 | |
27 | #include "../common/common.h" |
28 | |
29 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) |
30 | |
31 | /* |
32 | * ex_shell -- :sh[ell] |
33 | * Invoke the program named in the SHELL environment variable |
34 | * with the argument -i. |
35 | * |
36 | * PUBLIC: int ex_shell(SCR *, EXCMD *); |
37 | */ |
38 | int |
39 | ex_shell(SCR *sp, EXCMD *cmdp) |
40 | { |
41 | int rval; |
42 | char buf[PATH_MAX1024]; |
43 | |
44 | /* We'll need a shell. */ |
45 | if (opts_empty(sp, O_SHELL, 0)) |
46 | return (1); |
47 | |
48 | /* |
49 | * XXX |
50 | * Assumes all shells use -i. |
51 | */ |
52 | (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str)); |
53 | |
54 | /* Restore the window name. */ |
55 | (void)sp->gp->scr_rename(sp, NULL((void *)0), 0); |
56 | |
57 | /* If we're still in a vi screen, move out explicitly. */ |
58 | rval = ex_exec_proc(sp, cmdp, buf, NULL((void *)0), !F_ISSET(sp, SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000010)))); |
59 | |
60 | /* Set the window name. */ |
61 | (void)sp->gp->scr_rename(sp, sp->frp->name, 1); |
62 | |
63 | /* |
64 | * !!! |
65 | * Historically, vi didn't require a continue message after the |
66 | * return of the shell. Match it. |
67 | */ |
68 | F_SET(sp, SC_EX_WAIT_NO)(((sp)->flags) |= ((0x00080000))); |
69 | |
70 | return (rval); |
71 | } |
72 | |
73 | /* |
74 | * ex_exec_proc -- |
75 | * Run a separate process. |
76 | * |
77 | * PUBLIC: int ex_exec_proc(SCR *, EXCMD *, char *, const char *, int); |
78 | */ |
79 | int |
80 | ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg, |
81 | int need_newline) |
82 | { |
83 | GS *gp; |
84 | const char *name; |
85 | pid_t pid; |
86 | |
87 | gp = sp->gp; |
88 | |
89 | /* We'll need a shell. */ |
90 | if (opts_empty(sp, O_SHELL, 0)) |
91 | return (1); |
92 | |
93 | /* Enter ex mode. */ |
94 | if (F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) { |
95 | if (gp->scr_screen(sp, SC_EX0x00000001)) { |
96 | ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON); |
97 | return (1); |
98 | } |
99 | (void)gp->scr_attr(sp, SA_ALTERNATE, 0); |
100 | F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE)(((sp)->flags) |= ((0x00000004 | 0x00000010))); |
101 | } |
102 | |
103 | /* Put out additional newline, message. */ |
104 | if (need_newline) |
105 | (void)ex_puts(sp, "\n"); |
106 | if (msg != NULL((void *)0)) { |
107 | (void)ex_puts(sp, msg); |
108 | (void)ex_puts(sp, "\n"); |
109 | } |
110 | (void)ex_fflush(sp); |
111 | |
112 | switch (pid = vfork()) { |
Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function | |
113 | case -1: /* Error. */ |
114 | msgq(sp, M_SYSERR, "vfork"); |
115 | return (1); |
116 | case 0: /* Utility. */ |
117 | if ((name = strrchr(O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str), '/')) == NULL((void *)0)) |
118 | name = O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str); |
119 | else |
120 | ++name; |
121 | execl(O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str), name, "-c", cmd, (char *)NULL((void *)0)); |
122 | msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str), "execl: %s"); |
123 | _exit(127); |
124 | /* NOTREACHED */ |
125 | default: /* Parent. */ |
126 | return (proc_wait(sp, pid, cmd, 0, 0)); |
127 | } |
128 | /* NOTREACHED */ |
129 | } |
130 | |
131 | /* |
132 | * proc_wait -- |
133 | * Wait for one of the processes. |
134 | * |
135 | * !!! |
136 | * The pid_t type varies in size from a short to a long depending on the |
137 | * system. It has to be cast into something or the standard promotion |
138 | * rules get you. I'm using a long based on the belief that nobody is |
139 | * going to make it unsigned and it's unlikely to be a quad. |
140 | * |
141 | * PUBLIC: int proc_wait(SCR *, pid_t, const char *, int, int); |
142 | */ |
143 | int |
144 | proc_wait(SCR *sp, pid_t pid, const char *cmd, int silent, int okpipe) |
145 | { |
146 | size_t len; |
147 | int nf, pstat; |
148 | char *p; |
149 | |
150 | /* Wait for the utility, ignoring interruptions. */ |
151 | for (;;) { |
152 | errno(*__errno()) = 0; |
153 | if (waitpid(pid, &pstat, 0) != -1) |
154 | break; |
155 | if (errno(*__errno()) != EINTR4) { |
156 | msgq(sp, M_SYSERR, "waitpid"); |
157 | return (1); |
158 | } |
159 | } |
160 | |
161 | /* |
162 | * Display the utility's exit status. Ignore SIGPIPE from the |
163 | * parent-writer, as that only means that the utility chose to |
164 | * exit before reading all of its input. |
165 | */ |
166 | if (WIFSIGNALED(pstat)(((pstat) & 0177) != 0177 && ((pstat) & 0177) != 0) && (!okpipe || WTERMSIG(pstat)(((pstat) & 0177)) != SIGPIPE13)) { |
167 | for (; isblank(*cmd); ++cmd); |
168 | p = msg_print(sp, cmd, &nf); |
169 | len = strlen(p); |
170 | msgq(sp, M_ERR, "%.*s%s: received signal: %s%s", |
171 | MINIMUM(len, 20)(((len) < (20)) ? (len) : (20)), p, len > 20 ? " ..." : "", |
172 | strsignal(WTERMSIG(pstat)(((pstat) & 0177))), |
173 | WCOREDUMP(pstat)((pstat) & 0200) ? "; core dumped" : ""); |
174 | if (nf) |
175 | FREE_SPACE(sp, p, 0){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp != ((void *)0) && (p) == L__gp->tmp_bp ) (((L__gp)->flags) &= ~((0x0100))); else free(p); }; |
176 | return (1); |
177 | } |
178 | |
179 | if (WIFEXITED(pstat)(((pstat) & 0177) == 0) && WEXITSTATUS(pstat)(int)(((unsigned)(pstat) >> 8) & 0xff)) { |
180 | /* |
181 | * Remain silent for "normal" errors when doing shell file |
182 | * name expansions, they almost certainly indicate nothing |
183 | * more than a failure to match. |
184 | * |
185 | * Remain silent for vi read filter errors. It's historic |
186 | * practice. |
187 | */ |
188 | if (!silent) { |
189 | for (; isblank(*cmd); ++cmd); |
190 | p = msg_print(sp, cmd, &nf); |
191 | len = strlen(p); |
192 | msgq(sp, M_ERR, "%.*s%s: exited with status %d", |
193 | MINIMUM(len, 20)(((len) < (20)) ? (len) : (20)), p, len > 20 ? " ..." : "", |
194 | WEXITSTATUS(pstat)(int)(((unsigned)(pstat) >> 8) & 0xff)); |
195 | if (nf) |
196 | FREE_SPACE(sp, p, 0){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp != ((void *)0) && (p) == L__gp->tmp_bp ) (((L__gp)->flags) &= ~((0x0100))); else free(p); }; |
197 | } |
198 | return (1); |
199 | } |
200 | return (0); |
201 | } |