summaryrefslogtreecommitdiff
path: root/APACHE_1_3_42/src/ap/ap_execve.c
diff options
context:
space:
mode:
Diffstat (limited to 'APACHE_1_3_42/src/ap/ap_execve.c')
-rw-r--r--APACHE_1_3_42/src/ap/ap_execve.c349
1 files changed, 349 insertions, 0 deletions
diff --git a/APACHE_1_3_42/src/ap/ap_execve.c b/APACHE_1_3_42/src/ap/ap_execve.c
new file mode 100644
index 0000000000..0ce8b1826d
--- /dev/null
+++ b/APACHE_1_3_42/src/ap/ap_execve.c
@@ -0,0 +1,349 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Portions of this code are under this license:
+ *
+ * Copyright (c) 1980, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "httpd.h"
+
+/*---------------------------------------------------------------*/
+
+#ifdef NEED_HASHBANG_EMUL
+
+#undef execle
+#undef execve
+
+static const char **hashbang(const char *filename, char * const *argv);
+
+
+/* Historically, a list of arguments on the stack was often treated as
+ * being equivalent to an array (since they already were "contiguous"
+ * on the stack, and the arguments were pushed in the correct order).
+ * On today's processors, this is not necessarily equivalent, because
+ * often arguments are padded or passed partially in registers,
+ * or the stack direction is backwards.
+ * To be on the safe side, we copy the argument list to our own
+ * local argv[] array. The va_arg logic makes sure we do the right thing.
+ * XXX: malloc() is used because we expect to be overlaid soon.
+ */
+int ap_execle(const char *filename, const char *argv0, ...)
+{
+ va_list adummy;
+ char **envp;
+ char **argv;
+ int argc, ret;
+
+ /* First pass: Count arguments on stack */
+ va_start(adummy, argv0);
+ for (argc = 1; va_arg(adummy, char *) != NULL; ++argc) {
+ continue;
+ }
+ va_end(adummy);
+
+ if ((argv = (char **) malloc((argc + 2) * sizeof(*argv))) == NULL) {
+ fprintf(stderr, "Ouch! Out of memory in ap_execle()!\n");
+ return -1;
+ }
+
+ /* Pass two --- copy the argument strings into the result space */
+ va_start(adummy, argv0);
+ argv[0] = (char *)argv0;
+ for (argc = 1; (argv[argc] = va_arg(adummy, char *)) != NULL; ++argc) {
+ continue;
+ }
+ envp = va_arg(adummy, char **);
+ va_end(adummy);
+
+ ret = ap_execve(filename, argv, envp);
+ free(argv);
+
+ return ret;
+}
+
+/* Count number of entries in vector "args", including the trailing NULL entry
+ */
+static int
+count_args(char * const *args)
+{
+ int i;
+ for (i = 0; args[i] != NULL; ++i) {
+ continue;
+ }
+ return i+1;
+}
+
+/* Emulate the execve call, respecting a #!/interpreter line if present.
+ * On "real" unixes, the kernel does this.
+ * We have to fiddle with the argv array to make it work on platforms
+ * which don't support the "hashbang" interpreter line by default.
+ */
+int ap_execve(const char *filename, char * const argv[],
+ char * const envp[])
+{
+ char **script_argv;
+ extern char **environ;
+
+ if (envp == NULL) {
+ envp = (char * const *) environ;
+ }
+
+ /* Try to execute the file directly first: */
+ execve(filename, argv, envp);
+
+ /* Still with us? Then something went seriously wrong.
+ * From the (linux) man page:
+ * EACCES The file is not a regular file.
+ * EACCES Execute permission is denied for the file.
+ * EACCES Search permission is denied on a component of the path prefix.
+ * EPERM The file system is mounted noexec.
+ * EPERM The file system is mounted nosuid and the file has an SUID
+ * or SGID bit set.
+ * E2BIG The argument list is too big.
+ * ENOEXEC The magic number in the file is incorrect.
+ * EFAULT filename points outside your accessible address space.
+ * ENAMETOOLONG filename is too long.
+ * ENOENT The file does not exist.
+ * ENOMEM Insufficient kernel memory was available.
+ * ENOTDIR A component of the path prefix is not a directory.
+ * ELOOP filename contains a circular reference (i.e., via a symbolic link)
+ */
+
+ if (errno == ENOEXEC) {
+ /* Probably a script.
+ * Have a look; if there's a "#!" header then try to emulate
+ * the feature found in all modern OS's:
+ * Interpret the line following the #! as a command line
+ * in shell style.
+ */
+ if ((script_argv = (char **)hashbang(filename, argv)) != NULL) {
+
+ /* new filename is the interpreter to call */
+ filename = script_argv[0];
+
+ /* Restore argv[0] as on entry */
+ if (argv[0] != NULL) {
+ script_argv[0] = argv[0];
+ }
+
+ execve(filename, script_argv, envp);
+
+ free(script_argv);
+ }
+ /*
+ * Script doesn't start with a hashbang line!
+ * So, try to have the default shell execute it.
+ * For this, the size of argv must be increased by one
+ * entry: the shell's name. The remaining args are appended.
+ */
+ else {
+ int i = count_args(argv) + 1; /* +1 for leading SHELL_PATH */
+
+ if ((script_argv = malloc(sizeof(*script_argv) * i)) == NULL) {
+ fprintf(stderr, "Ouch! Out of memory in ap_execve()!\n");
+ return -1;
+ }
+
+ script_argv[0] = SHELL_PATH;
+
+ while (i > 0) {
+ script_argv[i] = argv[i-1];
+ --i;
+ }
+
+ execve(SHELL_PATH, script_argv, envp);
+
+ free(script_argv);
+ }
+ }
+ return -1;
+}
+
+/*---------------------------------------------------------------*/
+
+/*
+ * From: peter@zeus.dialix.oz.au (Peter Wemm)
+ * (taken from tcsh)
+ * If exec() fails look first for a #! [word] [word] ....
+ * If it is, splice the header into the argument list and retry.
+ * Return value: the original argv array (sans argv[0]), with the
+ * script's argument list prepended.
+ * XXX: malloc() is used so that everything can be free()ed after a failure.
+ */
+#define HACKBUFSZ 1024 /* Max chars in #! vector */
+#define HACKVECSZ 128 /* Max words in #! vector */
+static const char **hashbang(const char *filename, char * const *argv)
+{
+ char lbuf[HACKBUFSZ];
+ char *sargv[HACKVECSZ];
+ const char **newargv;
+ char *p, *ws;
+ int fd;
+ int sargc = 0;
+ int i, j;
+#ifdef WIN32
+ int fw = 0; /* found at least one word */
+ int first_word = 0;
+#endif /* WIN32 */
+
+ if ((fd = open(filename, O_RDONLY)) == -1) {
+ return NULL;
+ }
+
+ if (read(fd, (char *) lbuf, 2) != 2
+ || lbuf[0] != '#' || lbuf[1] != '!'
+ || read(fd, (char *) lbuf, HACKBUFSZ) <= 0) {
+ close(fd);
+ return NULL;
+ }
+
+ close(fd);
+
+ ws = NULL; /* word started = 0 */
+
+ for (p = lbuf; p < &lbuf[HACKBUFSZ];) {
+ switch (*p) {
+ case ' ':
+ case '\t':
+#ifdef NEW_CRLF
+ case '\r':
+#endif /*NEW_CRLF */
+ if (ws) { /* a blank after a word.. save it */
+ *p = '\0';
+#ifndef WIN32
+ if (sargc < HACKVECSZ - 1) {
+ sargv[sargc++] = ws;
+ }
+ ws = NULL;
+#else /* WIN32 */
+ if (sargc < HACKVECSZ - 1) {
+ sargv[sargc] = first_word ? NULL : hb_subst(ws);
+ if (sargv[sargc] == NULL) {
+ sargv[sargc] = ws;
+ }
+ sargc++;
+ }
+ ws = NULL;
+ fw = 1;
+ first_word = 1;
+#endif /* WIN32 */
+ }
+ p++;
+ continue;
+
+ case '\0': /* Whoa!! what the hell happened */
+ return NULL;
+
+ case '\n': /* The end of the line. */
+ if (
+#ifdef WIN32
+ fw ||
+#endif /* WIN32 */
+ ws) { /* terminate the last word */
+ *p = '\0';
+#ifndef WIN32
+ if (sargc < HACKVECSZ - 1) {
+ sargv[sargc++] = ws;
+ }
+#else /* WIN32 */
+ if (sargc < HACKVECSZ - 1) { /* deal with the 1-word case */
+ sargv[sargc] = first_word ? NULL : hb_subst(ws);
+ if (sargv[sargc] == NULL) {
+ sargv[sargc] = ws;
+ }
+ sargc++;
+ }
+#endif /* !WIN32 */
+ sargv[sargc] = NULL;
+ }
+ /* Count number of entries in the old argv vector */
+ for (i = 0; argv[i] != NULL; ++i) {
+ continue;
+ }
+ ++i;
+
+ newargv = (const char **) malloc((p - lbuf + 1)
+ + (i + sargc + 1) * sizeof(*newargv));
+ if (newargv == NULL) {
+ fprintf(stderr, "Ouch! Out of memory in hashbang()!\n");
+ return NULL;
+ }
+ ws = &((char *) newargv)[(i + sargc + 1) * sizeof(*newargv)];
+
+ /* Copy entries to allocated memory */
+ for (j = 0; j < sargc; ++j) {
+ newargv[j] = strcpy(ws, sargv[j]);
+ ws += strlen(ws) + 1; /* skip trailing '\0' */
+ }
+ newargv[sargc] = filename;
+
+ /* Append the old array. The old argv[0] is skipped. */
+ if (i > 1) {
+ memcpy(&newargv[sargc + 1], &argv[1],
+ (i - 1) * sizeof(*newargv));
+ }
+
+ newargv[sargc + i] = NULL;
+
+ ws = NULL;
+
+ return newargv;
+
+ default:
+ if (!ws) { /* Start a new word? */
+ ws = p;
+ }
+ p++;
+ break;
+ }
+ }
+ return NULL;
+}
+#else
+extern void ap_execve_is_not_here(void);
+void ap_execve_is_not_here(void) {}
+#endif /* NEED_HASHBANG_EMUL */