Imported Upstream version 1.7.4
[debian/sudo] / exec.c
1 /*
2  * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/socket.h>
22 #include <sys/stat.h>
23 #include <sys/time.h>
24 #include <sys/wait.h>
25 #ifdef HAVE_TERMIOS_H
26 # include <termios.h>
27 #else
28 # include <termio.h>
29 #endif /* HAVE_TERMIOS_H */
30 #include <sys/ioctl.h>
31 #ifdef HAVE_SYS_SELECT_H
32 # include <sys/select.h>
33 #endif /* HAVE_SYS_SELECT_H */
34 #include <stdio.h>
35 #ifdef STDC_HEADERS
36 # include <stdlib.h>
37 # include <stddef.h>
38 #else
39 # ifdef HAVE_STDLIB_H
40 #  include <stdlib.h>
41 # endif
42 #endif /* STDC_HEADERS */
43 #ifdef HAVE_STRING_H
44 # include <string.h>
45 #endif /* HAVE_STRING_H */
46 #ifdef HAVE_STRINGS_H
47 # include <strings.h>
48 #endif /* HAVE_STRINGS_H */
49 #ifdef HAVE_UNISTD_H
50 # include <unistd.h>
51 #endif /* HAVE_UNISTD_H */
52 #if TIME_WITH_SYS_TIME
53 # include <time.h>
54 #endif
55 #ifdef HAVE_SETLOCALE
56 # include <locale.h>
57 #endif
58 #include <errno.h>
59 #include <fcntl.h>
60 #include <signal.h>
61 #ifdef HAVE_SELINUX
62 # include <selinux/selinux.h>
63 #endif
64
65 #include "sudo.h"
66 #include "sudo_exec.h"
67
68 /* shared with exec_pty.c */
69 sig_atomic_t recvsig[NSIG];
70 void handler __P((int s));
71
72 /*
73  * Like execve(2) but falls back to running through /bin/sh
74  * ala execvp(3) if we get ENOEXEC.
75  */
76 int
77 my_execve(path, argv, envp)
78     const char *path;
79     char *argv[];
80     char *envp[];
81 {
82     execve(path, argv, envp);
83     if (errno == ENOEXEC) {
84         argv--;                 /* at least one extra slot... */
85         argv[0] = "sh";
86         argv[1] = (char *)path;
87         execve(_PATH_BSHELL, argv, envp);
88     }
89     return -1;
90 }
91
92 /*
93  * Fork and execute a command, returns the child's pid.
94  * Sends errno back on sv[1] if execve() fails.
95  */
96 static int fork_cmnd(path, argv, envp, sv, rbac_enabled)
97     const char *path;
98     char *argv[];
99     char *envp[];
100     int sv[2];
101     int rbac_enabled;
102 {
103     struct command_status cstat;
104     int pid;
105
106     pid = fork();
107     switch (pid) {
108     case -1:
109         error(1, "fork");
110         break;
111     case 0:
112         /* child */
113         close(sv[0]);
114         fcntl(sv[1], F_SETFD, FD_CLOEXEC);
115         if (exec_setup(rbac_enabled, user_ttypath, -1) == TRUE) {
116             /* headed for execve() */
117             closefrom(def_closefrom);
118 #ifdef HAVE_SELINUX
119             if (rbac_enabled)
120                 selinux_execve(path, argv, envp);
121             else
122 #endif
123                 my_execve(path, argv, envp);
124         }
125         cstat.type = CMD_ERRNO;
126         cstat.val = errno;
127         send(sv[1], &cstat, sizeof(cstat), 0);
128         _exit(1);
129     }
130     return pid;
131 }
132
133 /*
134  * Execute a command, potentially in a pty with I/O loggging.
135  * This is a little bit tricky due to how POSIX job control works and
136  * we fact that we have two different controlling terminals to deal with.
137  */
138 int
139 sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
140     const char *path;
141     char *argv[];
142     char *envp[];
143     uid_t uid;
144     struct command_status *cstat;
145     int dowait;
146     int bgmode;
147 {
148     sigaction_t sa;
149     fd_set *fdsr, *fdsw;
150     int maxfd, n, nready, status, sv[2];
151     int rbac_enabled = 0;
152     int log_io;
153     pid_t child;
154
155     /* If running in background mode, fork and exit. */
156     if (bgmode) {
157         switch (fork()) {
158             case -1:
159                 cstat->type = CMD_ERRNO;
160                 cstat->val = errno;
161                 return -1;
162             case 0:
163                 /* child continues */   
164                 break;
165             default:
166                 /* parent exits */
167                 exit(0);
168         }
169     }
170
171 #ifdef _PATH_SUDO_IO_LOGDIR
172     log_io = def_log_output || def_log_input || def_use_pty;
173     if (log_io) {
174         if (!bgmode)
175             pty_setup(uid);
176         io_log_open();
177         dowait = TRUE;
178     }
179 #endif /* _PATH_SUDO_IO_LOGDIR */
180
181 #ifdef HAVE_SELINUX
182     rbac_enabled = is_selinux_enabled() > 0 && user_role != NULL;
183     if (rbac_enabled)
184         dowait = TRUE;
185 #endif
186
187     /*
188      * If we don't need to wait for the command to finish, just exec it.
189      */
190     if (!dowait) {
191         exec_setup(FALSE, NULL, -1);
192         closefrom(def_closefrom);
193         my_execve(path, argv, envp);
194         cstat->type = CMD_ERRNO;
195         cstat->val = errno;
196         return(127);
197     }
198
199     /*
200      * We communicate with the child over a bi-directional pair of sockets.
201      * Parent sends signal info to child and child sends back wait status.
202      */
203     if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) != 0)
204         error(1, "cannot create sockets");
205
206     zero_bytes(&sa, sizeof(sa));
207     sigemptyset(&sa.sa_mask);
208
209     /* Note: HP-UX select() will not be interrupted if SA_RESTART set */
210     sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
211     sa.sa_handler = handler;
212     sigaction(SIGCHLD, &sa, NULL);
213     sigaction(SIGHUP, &sa, NULL);
214     sigaction(SIGINT, &sa, NULL);
215     sigaction(SIGPIPE, &sa, NULL);
216     sigaction(SIGQUIT, &sa, NULL);
217     sigaction(SIGTERM, &sa, NULL);
218
219     /* Max fd we will be selecting on. */
220     maxfd = sv[0];
221
222     /*
223      * Child will run the command in the pty, parent will pass data
224      * to and from pty.  Adjusts maxfd as needed.
225      */
226 #ifdef _PATH_SUDO_IO_LOGDIR
227     if (log_io)
228         child = fork_pty(path, argv, envp, sv, rbac_enabled, &maxfd);
229     else
230 #endif
231         child = fork_cmnd(path, argv, envp, sv, rbac_enabled);
232     close(sv[1]);
233
234 #ifdef HAVE_SETLOCALE
235     /*
236      * I/O logging must be in the C locale for floating point numbers
237      * to be logged consistently.
238      */
239     setlocale(LC_ALL, "C");
240 #endif
241
242     /*
243      * In the event loop we pass input from user tty to master
244      * and pass output from master to stdout and IO plugin.
245      */
246     fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
247     fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
248     for (;;) {
249         if (recvsig[SIGCHLD]) {
250             pid_t pid;
251
252             /*
253              * If logging I/O, child is the intermediate process,
254              * otherwise it is the command itself.
255              */
256             recvsig[SIGCHLD] = FALSE;
257             do {
258 #ifdef sudo_waitpid
259                 pid = sudo_waitpid(child, &status, WUNTRACED|WNOHANG);
260 #else
261                 pid = wait(&status);
262 #endif
263                 if (pid == child) {
264                     if (!log_io) {
265                         if (WIFSTOPPED(status)) {
266                             /* Child may not have privs to suspend us itself. */
267                             kill(getpid(), WSTOPSIG(status));
268                         } else {
269                             /* Child has exited, we are done. */
270                             cstat->type = CMD_WSTATUS;
271                             cstat->val = status;
272                             return 0;
273                         }
274                     }
275                     /* Else we get ECONNRESET on sv[0] if child dies. */
276                 }
277             } while (pid != -1 || errno == EINTR);
278         }
279
280         zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
281         zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
282
283         FD_SET(sv[0], fdsr);
284 #ifdef _PATH_SUDO_IO_LOGDIR
285         if (log_io)
286             fd_set_iobs(fdsr, fdsw); /* XXX - better name */
287 #endif
288         for (n = 0; n < NSIG; n++) {
289             if (recvsig[n] && n != SIGCHLD) {
290                 if (log_io) {
291                     FD_SET(sv[0], fdsw);
292                     break;
293                 } else {
294                     /* nothing listening on sv[0], send directly */
295                     kill(child, n);
296                 }
297             }
298         }
299
300         if (recvsig[SIGCHLD])
301             continue;
302         nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
303         if (nready == -1) {
304             if (errno == EINTR)
305                 continue;
306             error(1, "select failed");
307         }
308         if (FD_ISSET(sv[0], fdsr)) {
309             /* read child status */
310             n = recv(sv[0], cstat, sizeof(*cstat), 0);
311             if (n == -1) {
312                 if (errno == EINTR)
313                     continue;
314                 /*
315                  * If not logging I/O we will receive ECONNRESET when
316                  * the command is executed.  It is safe to ignore this.
317                  */
318                 if (log_io && errno != EAGAIN) {
319                     cstat->type = CMD_ERRNO;
320                     cstat->val = errno;
321                     break;
322                 }
323             }
324 #ifdef _PATH_SUDO_IO_LOGDIR /* XXX */
325             if (cstat->type == CMD_WSTATUS) {
326                 if (WIFSTOPPED(cstat->val)) {
327                     /* Suspend parent and tell child how to resume on return. */
328                     n = suspend_parent(WSTOPSIG(cstat->val));
329                     recvsig[n] = TRUE;
330                     continue;
331                 } else {
332                     /* Child exited or was killed, either way we are done. */
333                     break;
334                 }
335             } else
336 #endif /* _PATH_SUDO_IO_LOGDIR */
337             if (cstat->type == CMD_ERRNO) {
338                 /* Child was unable to execute command or broken pipe. */
339                 break;
340             }
341         }
342
343 #ifdef _PATH_SUDO_IO_LOGDIR
344         /* XXX - move this too */
345         if (FD_ISSET(sv[0], fdsw)) {
346             for (n = 0; n < NSIG; n++) {
347                 if (!recvsig[n])
348                     continue;
349                 recvsig[n] = FALSE;
350                 cstat->type = CMD_SIGNO;
351                 cstat->val = n;
352                 do {
353                     n = send(sv[0], cstat, sizeof(*cstat), 0);
354                 } while (n == -1 && errno == EINTR);
355                 if (n != sizeof(*cstat)) {
356                     recvsig[n] = TRUE;
357                     break;
358                 }
359             }
360         }
361         if (perform_io(fdsr, fdsw, cstat) != 0)
362             break;
363 #endif /* _PATH_SUDO_IO_LOGDIR */
364     }
365
366 #ifdef _PATH_SUDO_IO_LOGDIR
367     if (log_io) {
368         /* Flush any remaining output and free pty-related memory. */
369         pty_close(cstat);
370     }
371 #endif /* _PATH_SUDO_IO_LOGDIR */
372
373 #ifdef HAVE_SELINUX
374     if (rbac_enabled) {
375         /* This is probably not needed in log_io mode. */
376         if (selinux_restore_tty() != 0)
377             warningx("unable to restore tty label");
378     }
379 #endif
380
381     efree(fdsr);
382     efree(fdsw);
383
384     return cstat->type == CMD_ERRNO ? -1 : 0;
385 }
386
387 /*
388  * Generic handler for signals passed from parent -> child.
389  * The recvsig[] array is checked in the main event loop.
390  */
391 void
392 handler(s)
393     int s;
394 {
395     recvsig[s] = TRUE;
396 }