diff options
Diffstat (limited to 'APACHE_1_3_42/src/ap/ap_execve.c')
-rw-r--r-- | APACHE_1_3_42/src/ap/ap_execve.c | 349 |
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 */ |