1 /* Guts of POSIX spawn interface.  Generic POSIX.1 version.
2    Copyright (C) 2000-2006, 2008-2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17 
18 #include <config.h>
19 
20 /* Specification.  */
21 #include <spawn.h>
22 #include "spawn_int.h"
23 
24 #include <alloca.h>
25 #include <errno.h>
26 
27 #include <fcntl.h>
28 #ifndef O_LARGEFILE
29 # define O_LARGEFILE 0
30 #endif
31 
32 #if _LIBC || HAVE_PATHS_H
33 # include <paths.h>
34 #else
35 # define _PATH_BSHELL "/bin/sh"
36 #endif
37 
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #if _LIBC
44 # include <not-cancel.h>
45 #else
46 # define close_not_cancel close
47 # define open_not_cancel open
48 #endif
49 
50 #if _LIBC
51 # include <local-setxid.h>
52 #else
53 # if !HAVE_SETEUID
54 #  define seteuid(id) setresuid (-1, id, -1)
55 # endif
56 # if !HAVE_SETEGID
57 #  define setegid(id) setresgid (-1, id, -1)
58 # endif
59 # define local_seteuid(id) seteuid (id)
60 # define local_setegid(id) setegid (id)
61 #endif
62 
63 #if _LIBC
64 # define alloca __alloca
65 # define execve __execve
66 # define dup2 __dup2
67 # define fork __fork
68 # define getgid __getgid
69 # define getuid __getuid
70 # define sched_setparam __sched_setparam
71 # define sched_setscheduler __sched_setscheduler
72 # define setpgid __setpgid
73 # define sigaction __sigaction
74 # define sigismember __sigismember
75 # define sigprocmask __sigprocmask
76 # define strchrnul __strchrnul
77 # define vfork __vfork
78 #else
79 # undef internal_function
80 # define internal_function /* empty */
81 #endif
82 
83 
84 /* The Unix standard contains a long explanation of the way to signal
85    an error after the fork() was successful.  Since no new wait status
86    was wanted there is no way to signal an error using one of the
87    available methods.  The committee chose to signal an error by a
88    normal program exit with the exit code 127.  */
89 #define SPAWN_ERROR     127
90 
91 
92 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
93 
94 /* Native Windows API.  */
95 int
__spawni(pid_t * pid,const char * file,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[],int use_path)96 __spawni (pid_t *pid, const char *file,
97           const posix_spawn_file_actions_t *file_actions,
98           const posix_spawnattr_t *attrp, char *const argv[],
99           char *const envp[], int use_path)
100 {
101   /* Not yet implemented.  */
102   return ENOSYS;
103 }
104 
105 #else
106 
107 
108 /* The file is accessible but it is not an executable file.  Invoke
109    the shell to interpret it as a script.  */
110 static void
111 internal_function
script_execute(const char * file,char * const argv[],char * const envp[])112 script_execute (const char *file, char *const argv[], char *const envp[])
113 {
114   /* Count the arguments.  */
115   int argc = 0;
116   while (argv[argc++])
117     ;
118 
119   /* Construct an argument list for the shell.  */
120   {
121     char **new_argv = (char **) alloca ((argc + 1) * sizeof (char *));
122     new_argv[0] = (char *) _PATH_BSHELL;
123     new_argv[1] = (char *) file;
124     while (argc > 1)
125       {
126         new_argv[argc] = argv[argc - 1];
127         --argc;
128       }
129 
130     /* Execute the shell.  */
131     execve (new_argv[0], new_argv, envp);
132   }
133 }
134 
135 
136 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
137    Before running the process perform the actions described in FILE-ACTIONS. */
138 int
__spawni(pid_t * pid,const char * file,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[],int use_path)139 __spawni (pid_t *pid, const char *file,
140           const posix_spawn_file_actions_t *file_actions,
141           const posix_spawnattr_t *attrp, char *const argv[],
142           char *const envp[], int use_path)
143 {
144   pid_t new_pid;
145   char *path, *p, *name;
146   size_t len;
147   size_t pathlen;
148 
149   /* Do this once.  */
150   short int flags = attrp == NULL ? 0 : attrp->_flags;
151 
152   /* Avoid gcc warning
153        "variable 'flags' might be clobbered by 'longjmp' or 'vfork'"  */
154   (void) &flags;
155 
156   /* Generate the new process.  */
157 #if HAVE_VFORK
158   if ((flags & POSIX_SPAWN_USEVFORK) != 0
159       /* If no major work is done, allow using vfork.  Note that we
160          might perform the path searching.  But this would be done by
161          a call to execvp(), too, and such a call must be OK according
162          to POSIX.  */
163       || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
164                     | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
165                     | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
166           && file_actions == NULL))
167     new_pid = vfork ();
168   else
169 #endif
170     new_pid = fork ();
171 
172   if (new_pid != 0)
173     {
174       if (new_pid < 0)
175         return errno;
176 
177       /* The call was successful.  Store the PID if necessary.  */
178       if (pid != NULL)
179         *pid = new_pid;
180 
181       return 0;
182     }
183 
184   /* Set signal mask.  */
185   if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
186       && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
187     _exit (SPAWN_ERROR);
188 
189   /* Set signal default action.  */
190   if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
191     {
192       /* We have to iterate over all signals.  This could possibly be
193          done better but it requires system specific solutions since
194          the sigset_t data type can be very different on different
195          architectures.  */
196       int sig;
197       struct sigaction sa;
198 
199       memset (&sa, '\0', sizeof (sa));
200       sa.sa_handler = SIG_DFL;
201 
202       for (sig = 1; sig <= NSIG; ++sig)
203         if (sigismember (&attrp->_sd, sig) != 0
204             && sigaction (sig, &sa, NULL) != 0)
205           _exit (SPAWN_ERROR);
206 
207     }
208 
209 #if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
210   /* Set the scheduling algorithm and parameters.  */
211   if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
212       == POSIX_SPAWN_SETSCHEDPARAM)
213     {
214       if (sched_setparam (0, &attrp->_sp) == -1)
215         _exit (SPAWN_ERROR);
216     }
217   else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
218     {
219       if (sched_setscheduler (0, attrp->_policy,
220                               (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
221                               ? &attrp->_sp : NULL) == -1)
222         _exit (SPAWN_ERROR);
223     }
224 #endif
225 
226   /* Set the process group ID.  */
227   if ((flags & POSIX_SPAWN_SETPGROUP) != 0
228       && setpgid (0, attrp->_pgrp) != 0)
229     _exit (SPAWN_ERROR);
230 
231   /* Set the effective user and group IDs.  */
232   if ((flags & POSIX_SPAWN_RESETIDS) != 0
233       && (local_seteuid (getuid ()) != 0
234           || local_setegid (getgid ()) != 0))
235     _exit (SPAWN_ERROR);
236 
237   /* Execute the file actions.  */
238   if (file_actions != NULL)
239     {
240       int cnt;
241 
242       for (cnt = 0; cnt < file_actions->_used; ++cnt)
243         {
244           struct __spawn_action *action = &file_actions->_actions[cnt];
245 
246           switch (action->tag)
247             {
248             case spawn_do_close:
249               if (close_not_cancel (action->action.close_action.fd) != 0)
250                 /* Signal the error.  */
251                 _exit (SPAWN_ERROR);
252               break;
253 
254             case spawn_do_open:
255               {
256                 int new_fd = open_not_cancel (action->action.open_action.path,
257                                               action->action.open_action.oflag
258                                               | O_LARGEFILE,
259                                               action->action.open_action.mode);
260 
261                 if (new_fd == -1)
262                   /* The 'open' call failed.  */
263                   _exit (SPAWN_ERROR);
264 
265                 /* Make sure the desired file descriptor is used.  */
266                 if (new_fd != action->action.open_action.fd)
267                   {
268                     if (dup2 (new_fd, action->action.open_action.fd)
269                         != action->action.open_action.fd)
270                       /* The 'dup2' call failed.  */
271                       _exit (SPAWN_ERROR);
272 
273                     if (close_not_cancel (new_fd) != 0)
274                       /* The 'close' call failed.  */
275                       _exit (SPAWN_ERROR);
276                   }
277               }
278               break;
279 
280             case spawn_do_dup2:
281               if (dup2 (action->action.dup2_action.fd,
282                         action->action.dup2_action.newfd)
283                   != action->action.dup2_action.newfd)
284                 /* The 'dup2' call failed.  */
285                 _exit (SPAWN_ERROR);
286               break;
287             }
288         }
289     }
290 
291   if (! use_path || strchr (file, '/') != NULL)
292     {
293       /* The FILE parameter is actually a path.  */
294       execve (file, argv, envp);
295 
296       if (errno == ENOEXEC)
297         script_execute (file, argv, envp);
298 
299       /* Oh, oh.  'execve' returns.  This is bad.  */
300       _exit (SPAWN_ERROR);
301     }
302 
303   /* We have to search for FILE on the path.  */
304   path = getenv ("PATH");
305   if (path == NULL)
306     {
307 #if HAVE_CONFSTR
308       /* There is no 'PATH' in the environment.
309          The default search path is the current directory
310          followed by the path 'confstr' returns for '_CS_PATH'.  */
311       len = confstr (_CS_PATH, (char *) NULL, 0);
312       path = (char *) alloca (1 + len);
313       path[0] = ':';
314       (void) confstr (_CS_PATH, path + 1, len);
315 #else
316       /* Pretend that the PATH contains only the current directory.  */
317       path = "";
318 #endif
319     }
320 
321   len = strlen (file) + 1;
322   pathlen = strlen (path);
323   name = alloca (pathlen + len + 1);
324   /* Copy the file name at the top.  */
325   name = (char *) memcpy (name + pathlen + 1, file, len);
326   /* And add the slash.  */
327   *--name = '/';
328 
329   p = path;
330   do
331     {
332       char *startp;
333 
334       path = p;
335       p = strchrnul (path, ':');
336 
337       if (p == path)
338         /* Two adjacent colons, or a colon at the beginning or the end
339            of 'PATH' means to search the current directory.  */
340         startp = name + 1;
341       else
342         startp = (char *) memcpy (name - (p - path), path, p - path);
343 
344       /* Try to execute this name.  If it works, execv will not return.  */
345       execve (startp, argv, envp);
346 
347       if (errno == ENOEXEC)
348         script_execute (startp, argv, envp);
349 
350       switch (errno)
351         {
352         case EACCES:
353         case ENOENT:
354         case ESTALE:
355         case ENOTDIR:
356           /* Those errors indicate the file is missing or not executable
357              by us, in which case we want to just try the next path
358              directory.  */
359           break;
360 
361         default:
362           /* Some other error means we found an executable file, but
363              something went wrong executing it; return the error to our
364              caller.  */
365           _exit (SPAWN_ERROR);
366         }
367     }
368   while (*p++ != '\0');
369 
370   /* Return with an error.  */
371   _exit (SPAWN_ERROR);
372 }
373 
374 #endif
375