]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/exec.c
libfido2: update to 1.13.0
[FreeBSD/FreeBSD.git] / lib / libc / gen / exec.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1991, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __SCCSID("@(#)exec.c    8.1 (Berkeley) 6/4/93");
34 #include "namespace.h"
35 #include <sys/param.h>
36 #include <sys/stat.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <paths.h>
43
44 #include <stdarg.h>
45 #include "un-namespace.h"
46 #include "libc_private.h"
47
48 static const char execvPe_err_preamble[] = "execvP: ";
49 static const char execvPe_err_trailer[] = ": path too long\n";
50
51 int
52 execl(const char *name, const char *arg, ...)
53 {
54         va_list ap;
55         const char **argv;
56         int n;
57
58         va_start(ap, arg);
59         n = 1;
60         while (va_arg(ap, char *) != NULL)
61                 n++;
62         va_end(ap);
63         argv = alloca((n + 1) * sizeof(*argv));
64         if (argv == NULL) {
65                 errno = ENOMEM;
66                 return (-1);
67         }
68         va_start(ap, arg);
69         n = 1;
70         argv[0] = arg;
71         while ((argv[n] = va_arg(ap, char *)) != NULL)
72                 n++;
73         va_end(ap);
74         return (_execve(name, __DECONST(char **, argv), environ));
75 }
76
77 int
78 execle(const char *name, const char *arg, ...)
79 {
80         va_list ap;
81         const char **argv;
82         char **envp;
83         int n;
84
85         va_start(ap, arg);
86         n = 1;
87         while (va_arg(ap, char *) != NULL)
88                 n++;
89         va_end(ap);
90         argv = alloca((n + 1) * sizeof(*argv));
91         if (argv == NULL) {
92                 errno = ENOMEM;
93                 return (-1);
94         }
95         va_start(ap, arg);
96         n = 1;
97         argv[0] = arg;
98         while ((argv[n] = va_arg(ap, char *)) != NULL)
99                 n++;
100         envp = va_arg(ap, char **);
101         va_end(ap);
102         return (_execve(name, __DECONST(char **, argv), envp));
103 }
104
105 int
106 execlp(const char *name, const char *arg, ...)
107 {
108         va_list ap;
109         const char **argv;
110         int n;
111
112         va_start(ap, arg);
113         n = 1;
114         while (va_arg(ap, char *) != NULL)
115                 n++;
116         va_end(ap);
117         argv = alloca((n + 1) * sizeof(*argv));
118         if (argv == NULL) {
119                 errno = ENOMEM;
120                 return (-1);
121         }
122         va_start(ap, arg);
123         n = 1;
124         argv[0] = arg;
125         while ((argv[n] = va_arg(ap, char *)) != NULL)
126                 n++;
127         va_end(ap);
128         return (execvp(name, __DECONST(char **, argv)));
129 }
130
131 int
132 execv(const char *name, char * const *argv)
133 {
134         (void)_execve(name, argv, environ);
135         return (-1);
136 }
137
138 int
139 execvp(const char *name, char * const *argv)
140 {
141         return (_execvpe(name, argv, environ));
142 }
143
144 static int
145 execvPe(const char *name, const char *path, char * const *argv,
146     char * const *envp)
147 {
148         const char **memp;
149         size_t cnt, lp, ln;
150         int eacces, save_errno;
151         char buf[MAXPATHLEN];
152         const char *bp, *np, *op, *p;
153         struct stat sb;
154
155         eacces = 0;
156
157         /* If it's an absolute or relative path name, it's easy. */
158         if (strchr(name, '/')) {
159                 bp = name;
160                 op = NULL;
161                 goto retry;
162         }
163         bp = buf;
164
165         /* If it's an empty path name, fail in the usual POSIX way. */
166         if (*name == '\0') {
167                 errno = ENOENT;
168                 return (-1);
169         }
170
171         op = path;
172         ln = strlen(name);
173         while (op != NULL) {
174                 np = strchrnul(op, ':');
175
176                 /*
177                  * It's a SHELL path -- double, leading and trailing colons
178                  * mean the current directory.
179                  */
180                 if (np == op) {
181                         /* Empty component. */
182                         p = ".";
183                         lp = 1;
184                 } else {
185                         /* Non-empty component. */
186                         p = op;
187                         lp = np - op;
188                 }
189
190                 /* Advance to the next component or terminate after this. */
191                 if (*np == '\0')
192                         op = NULL;
193                 else
194                         op = np + 1;
195
196                 /*
197                  * If the path is too long complain.  This is a possible
198                  * security issue; given a way to make the path too long
199                  * the user may execute the wrong program.
200                  */
201                 if (lp + ln + 2 > sizeof(buf)) {
202                         (void)_write(STDERR_FILENO, execvPe_err_preamble,
203                             sizeof(execvPe_err_preamble) - 1);
204                         (void)_write(STDERR_FILENO, p, lp);
205                         (void)_write(STDERR_FILENO, execvPe_err_trailer,
206                             sizeof(execvPe_err_trailer) - 1);
207                         continue;
208                 }
209                 bcopy(p, buf, lp);
210                 buf[lp] = '/';
211                 bcopy(name, buf + lp + 1, ln);
212                 buf[lp + ln + 1] = '\0';
213
214 retry:          (void)_execve(bp, argv, envp);
215                 switch (errno) {
216                 case E2BIG:
217                         goto done;
218                 case ELOOP:
219                 case ENAMETOOLONG:
220                 case ENOENT:
221                         break;
222                 case ENOEXEC:
223                         for (cnt = 0; argv[cnt]; ++cnt)
224                                 ;
225
226                         /*
227                          * cnt may be 0 above; always allocate at least
228                          * 3 entries so that we can at least fit "sh", bp, and
229                          * the NULL terminator.  We can rely on cnt to take into
230                          * account the NULL terminator in all other scenarios,
231                          * as we drop argv[0].
232                          */
233                         memp = alloca(MAX(3, cnt + 2) * sizeof(char *));
234                         if (memp == NULL) {
235                                 /* errno = ENOMEM; XXX override ENOEXEC? */
236                                 goto done;
237                         }
238                         if (cnt > 0) {
239                                 memp[0] = argv[0];
240                                 memp[1] = bp;
241                                 bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
242                         } else {
243                                 memp[0] = "sh";
244                                 memp[1] = bp;
245                                 memp[2] = NULL;
246                         }
247                         (void)_execve(_PATH_BSHELL,
248                             __DECONST(char **, memp), envp);
249                         goto done;
250                 case ENOMEM:
251                         goto done;
252                 case ENOTDIR:
253                         break;
254                 case ETXTBSY:
255                         /*
256                          * We used to retry here, but sh(1) doesn't.
257                          */
258                         goto done;
259                 default:
260                         /*
261                          * EACCES may be for an inaccessible directory or
262                          * a non-executable file.  Call stat() to decide
263                          * which.  This also handles ambiguities for EFAULT
264                          * and EIO, and undocumented errors like ESTALE.
265                          * We hope that the race for a stat() is unimportant.
266                          */
267                         save_errno = errno;
268                         if (stat(bp, &sb) != 0)
269                                 break;
270                         if (save_errno == EACCES) {
271                                 eacces = 1;
272                                 continue;
273                         }
274                         errno = save_errno;
275                         goto done;
276                 }
277         }
278         if (eacces)
279                 errno = EACCES;
280         else
281                 errno = ENOENT;
282 done:
283         return (-1);
284 }
285
286 int
287 execvP(const char *name, const char *path, char * const argv[])
288 {
289         return execvPe(name, path, argv, environ);
290 }
291
292 int
293 _execvpe(const char *name, char * const argv[], char * const envp[])
294 {
295         const char *path;
296
297         /* Get the path we're searching. */
298         if ((path = getenv("PATH")) == NULL)
299                 path = _PATH_DEFPATH;
300
301         return (execvPe(name, path, argv, envp));
302 }