xref: /openbsd/lib/libc/gen/exec.c (revision 09467b48)
1 /*	$OpenBSD: exec.c,v 1.23 2016/03/13 18:34:20 guenther Exp $ */
2 /*-
3  * Copyright (c) 1991, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/uio.h>
33 
34 #include <errno.h>
35 #include <limits.h>
36 #include <paths.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 int
44 execl(const char *name, const char *arg, ...)
45 {
46 	va_list ap;
47 	char **argv;
48 	int n;
49 
50 	va_start(ap, arg);
51 	n = 1;
52 	while (va_arg(ap, char *) != NULL)
53 		n++;
54 	va_end(ap);
55 	argv = alloca((n + 1) * sizeof(*argv));
56 	if (argv == NULL) {
57 		errno = ENOMEM;
58 		return (-1);
59 	}
60 	va_start(ap, arg);
61 	n = 1;
62 	argv[0] = (char *)arg;
63 	while ((argv[n] = va_arg(ap, char *)) != NULL)
64 		n++;
65 	va_end(ap);
66 	return (execve(name, argv, environ));
67 }
68 DEF_WEAK(execl);
69 
70 int
71 execle(const char *name, const char *arg, ...)
72 {
73 	va_list ap;
74 	char **argv, **envp;
75 	int n;
76 
77 	va_start(ap, arg);
78 	n = 1;
79 	while (va_arg(ap, char *) != NULL)
80 		n++;
81 	va_end(ap);
82 	argv = alloca((n + 1) * sizeof(*argv));
83 	if (argv == NULL) {
84 		errno = ENOMEM;
85 		return (-1);
86 	}
87 	va_start(ap, arg);
88 	n = 1;
89 	argv[0] = (char *)arg;
90 	while ((argv[n] = va_arg(ap, char *)) != NULL)
91 		n++;
92 	envp = va_arg(ap, char **);
93 	va_end(ap);
94 	return (execve(name, argv, envp));
95 }
96 
97 int
98 execlp(const char *name, const char *arg, ...)
99 {
100 	va_list ap;
101 	char **argv;
102 	int n;
103 
104 	va_start(ap, arg);
105 	n = 1;
106 	while (va_arg(ap, char *) != NULL)
107 		n++;
108 	va_end(ap);
109 	argv = alloca((n + 1) * sizeof(*argv));
110 	if (argv == NULL) {
111 		errno = ENOMEM;
112 		return (-1);
113 	}
114 	va_start(ap, arg);
115 	n = 1;
116 	argv[0] = (char *)arg;
117 	while ((argv[n] = va_arg(ap, char *)) != NULL)
118 		n++;
119 	va_end(ap);
120 	return (execvp(name, argv));
121 }
122 
123 int
124 execv(const char *name, char *const *argv)
125 {
126 	(void)execve(name, argv, environ);
127 	return (-1);
128 }
129 
130 int
131 execvpe(const char *name, char *const *argv, char *const *envp)
132 {
133 	char **memp;
134 	int cnt;
135 	size_t lp, ln, len;
136 	char *p;
137 	int eacces = 0;
138 	char *bp, *cur, *path, buf[PATH_MAX];
139 
140 	/*
141 	 * Do not allow null name
142 	 */
143 	if (name == NULL || *name == '\0') {
144 		errno = ENOENT;
145 		return (-1);
146  	}
147 
148 	/* If it's an absolute or relative path name, it's easy. */
149 	if (strchr(name, '/')) {
150 		bp = (char *)name;
151 		cur = path = NULL;
152 		goto retry;
153 	}
154 	bp = buf;
155 
156 	/* Get the path we're searching. */
157 	if (!(path = getenv("PATH")))
158 		path = _PATH_DEFPATH;
159 	len = strlen(path) + 1;
160 	cur = alloca(len);
161 	if (cur == NULL) {
162 		errno = ENOMEM;
163 		return (-1);
164 	}
165 	strlcpy(cur, path, len);
166 	path = cur;
167 	while ((p = strsep(&cur, ":"))) {
168 		/*
169 		 * It's a SHELL path -- double, leading and trailing colons
170 		 * mean the current directory.
171 		 */
172 		if (!*p) {
173 			p = ".";
174 			lp = 1;
175 		} else
176 			lp = strlen(p);
177 		ln = strlen(name);
178 
179 		/*
180 		 * If the path is too long complain.  This is a possible
181 		 * security issue; given a way to make the path too long
182 		 * the user may execute the wrong program.
183 		 */
184 		if (lp + ln + 2 > sizeof(buf)) {
185 			struct iovec iov[3];
186 
187 			iov[0].iov_base = "execvp: ";
188 			iov[0].iov_len = 8;
189 			iov[1].iov_base = p;
190 			iov[1].iov_len = lp;
191 			iov[2].iov_base = ": path too long\n";
192 			iov[2].iov_len = 16;
193 			(void)writev(STDERR_FILENO, iov, 3);
194 			continue;
195 		}
196 		bcopy(p, buf, lp);
197 		buf[lp] = '/';
198 		bcopy(name, buf + lp + 1, ln);
199 		buf[lp + ln + 1] = '\0';
200 
201 retry:		(void)execve(bp, argv, envp);
202 		switch(errno) {
203 		case E2BIG:
204 			goto done;
205 		case EISDIR:
206 		case ELOOP:
207 		case ENAMETOOLONG:
208 		case ENOENT:
209 			break;
210 		case ENOEXEC:
211 			for (cnt = 0; argv[cnt]; ++cnt)
212 				;
213 			memp = alloca((cnt + 2) * sizeof(char *));
214 			if (memp == NULL)
215 				goto done;
216 			memp[0] = "sh";
217 			memp[1] = bp;
218 			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
219 			(void)execve(_PATH_BSHELL, memp, envp);
220 			goto done;
221 		case ENOMEM:
222 			goto done;
223 		case ENOTDIR:
224 			break;
225 		case ETXTBSY:
226 			/*
227 			 * We used to retry here, but sh(1) doesn't.
228 			 */
229 			goto done;
230 		case EACCES:
231 			eacces = 1;
232 			break;
233 		default:
234 			goto done;
235 		}
236 	}
237 	if (eacces)
238 		errno = EACCES;
239 	else if (!errno)
240 		errno = ENOENT;
241 done:
242 	return (-1);
243 }
244 DEF_WEAK(execvpe);
245 
246 int
247 execvp(const char *name, char *const *argv)
248 {
249     return execvpe(name, argv, environ);
250 }
251 DEF_WEAK(execvp);
252 
253