home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / ap / ap_execve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-01  |  12.1 KB  |  383 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1998-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  */
  57.  
  58. /*
  59.  * Portions of this code are under this license:
  60.  *
  61.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  62.  * All rights reserved.
  63.  *
  64.  * Redistribution and use in source and binary forms, with or without
  65.  * modification, are permitted provided that the following conditions
  66.  * are met:
  67.  * 1. Redistributions of source code must retain the above copyright
  68.  *    notice, this list of conditions and the following disclaimer.
  69.  * 2. Redistributions in binary form must reproduce the above copyright
  70.  *    notice, this list of conditions and the following disclaimer in the
  71.  *    documentation and/or other materials provided with the distribution.
  72.  * 3. All advertising materials mentioning features or use of this software
  73.  *    must display the following acknowledgement:
  74.  *    This product includes software developed by the University of
  75.  *    California, Berkeley and its contributors.
  76.  * 4. Neither the name of the University nor the names of its contributors
  77.  *    may be used to endorse or promote products derived from this software
  78.  *    without specific prior written permission.
  79.  *
  80.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  81.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  82.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  83.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  84.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  85.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  86.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  87.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  88.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  89.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  90.  * SUCH DAMAGE.
  91.  */
  92.  
  93. #include "httpd.h"
  94.  
  95. /*---------------------------------------------------------------*/
  96.  
  97. #ifdef NEED_HASHBANG_EMUL
  98.  
  99. #undef execle
  100. #undef execve
  101.  
  102. static const char **hashbang(const char *filename, char **argv);
  103.  
  104.  
  105. /* Historically, a list of arguments on the stack was often treated as
  106.  * being equivalent to an array (since they already were "contiguous"
  107.  * on the stack, and the arguments were pushed in the correct order).
  108.  * On today's processors, this is not necessarily equivalent, because
  109.  * often arguments are padded or passed partially in registers,
  110.  * or the stack direction is backwards.
  111.  * To be on the safe side, we copy the argument list to our own
  112.  * local argv[] array. The va_arg logic makes sure we do the right thing.
  113.  * XXX: malloc() is used because we expect to be overlaid soon.
  114.  */
  115. int ap_execle(const char *filename, const char *argv0, ...)
  116. {
  117.     va_list adummy;
  118.     char **envp;
  119.     char **argv;
  120.     int argc, ret;
  121.  
  122.     /* First pass: Count arguments on stack */
  123.     va_start(adummy, argv0);
  124.     for (argc = 1; va_arg(adummy, char *) != NULL; ++argc) {
  125.     continue;
  126.     }
  127.     va_end(adummy);
  128.  
  129.     if ((argv = (char **) malloc((argc + 2) * sizeof(*argv))) == NULL)
  130.     return -1;
  131.  
  132.     /* Pass two --- copy the argument strings into the result space */
  133.     va_start(adummy, argv0);
  134.     argv[0] = argv0;
  135.     for (argc = 1; (argv[argc] = va_arg(adummy, char *)) != NULL; ++argc) {
  136.     continue;
  137.     }
  138.     envp = va_arg(adummy, char **);
  139.     va_end(adummy);
  140.  
  141.     ret = ap_execve(filename, argv, envp);
  142.     free(argv);
  143.  
  144.     return ret;
  145. }
  146.  
  147. /* Count number of entries in vector "args", including the trailing NULL entry
  148.  */
  149. static int
  150. count_args(const char **args)
  151. {
  152.     int i;
  153.     for (i = 0; args[i] != NULL; ++i) {
  154.     continue;
  155.     }
  156.     return i+1;
  157. }
  158.  
  159. /* Emulate the execve call, respecting a #!/interpreter line if present.
  160.  * On "real" unixes, the kernel does this.
  161.  * We have to fiddle with the argv array to make it work on platforms
  162.  * which don't support the "hashbang" interpreter line by default.
  163.  */
  164. int ap_execve(const char *filename, const char *argv[],
  165.           const char *envp[])
  166. {
  167.     const char **script_argv;
  168.     extern char **environ;
  169.  
  170.     if (envp == NULL) {
  171.     envp = (const char **) environ;
  172.     }
  173.  
  174.     /* Try to execute the file directly first: */
  175.     execve(filename, argv, envp);
  176.  
  177.     /* Still with us? Then something went seriously wrong.
  178.      * From the (linux) man page:
  179.      * EACCES The file is not a regular file.
  180.      * EACCES Execute permission is denied for the file.
  181.      * EACCES Search  permission  is denied on a component of the path prefix.
  182.      * EPERM  The file system is mounted noexec.
  183.      * EPERM  The file system is mounted nosuid and the file  has an SUID
  184.      *        or SGID bit set.
  185.      * E2BIG  The argument list is too big.
  186.      * ENOEXEC The magic number in the file is incorrect.
  187.      * EFAULT filename  points  outside  your  accessible address space.
  188.      * ENAMETOOLONG filename is too long.
  189.      * ENOENT The file does not exist.
  190.      * ENOMEM Insufficient kernel memory was available.
  191.      * ENOTDIR A component of the path prefix is not a  directory.
  192.      * ELOOP  filename contains a circular reference (i.e., via a symbolic link)
  193.      */
  194.  
  195.     if (errno == ENOEXEC) {
  196.     /* Probably a script.
  197.      * Have a look; if there's a "#!" header then try to emulate
  198.      * the feature found in all modern OS's:
  199.      * Interpret the line following the #! as a command line
  200.      * in shell style.
  201.      */
  202.     if ((script_argv = hashbang(filename, argv)) != NULL) {
  203.  
  204.         /* new filename is the interpreter to call */
  205.         filename = script_argv[0];
  206.  
  207.         /* Restore argv[0] as on entry */
  208.         if (argv[0] != NULL) {
  209.         script_argv[0] = argv[0];
  210.         }
  211.  
  212.         execve(filename, script_argv, envp);
  213.  
  214.         free(script_argv);
  215.     }
  216.     /*
  217.      * Script doesn't start with a hashbang line!
  218.      * So, try to have the default shell execute it.
  219.      * For this, the size of argv must be increased by one
  220.      * entry: the shell's name. The remaining args are appended.
  221.      */
  222.     else {
  223.         int i = count_args(argv) + 1;   /* +1 for leading SHELL_PATH */
  224.  
  225.         if ((script_argv = malloc(sizeof(*script_argv) * i)) == NULL)
  226.         return -1;
  227.  
  228.         script_argv[0] = SHELL_PATH;
  229.  
  230.         while (i > 0) {
  231.         script_argv[i] = argv[i-1];
  232.         --i;
  233.         }
  234.  
  235.         execve(SHELL_PATH, script_argv, envp);
  236.  
  237.         free(script_argv);
  238.     }
  239.     }
  240.     return -1;
  241. }
  242.  
  243. /*---------------------------------------------------------------*/
  244.  
  245. /*
  246.  * From: peter@zeus.dialix.oz.au (Peter Wemm)
  247.  * (taken from tcsh)
  248.  * If exec() fails look first for a #! [word] [word] ....
  249.  * If it is, splice the header into the argument list and retry.
  250.  * Return value: the original argv array (sans argv[0]), with the
  251.  * script's argument list prepended.
  252.  * XXX: malloc() is used so that everything can be free()ed after a failure.
  253.  */
  254. #define HACKBUFSZ 1024        /* Max chars in #! vector */
  255. #define HACKVECSZ 128        /* Max words in #! vector */
  256. static const char **hashbang(const char *filename, char **argv)
  257. {
  258.     char lbuf[HACKBUFSZ];
  259.     char *sargv[HACKVECSZ];
  260.     const char **newargv;
  261.     char *p, *ws;
  262.     int fd;
  263.     int sargc = 0;
  264.     int i, j;
  265. #ifdef WIN32
  266.     int fw = 0;            /* found at least one word */
  267.     int first_word = 0;
  268. #endif /* WIN32 */
  269.  
  270.     if ((fd = open(filename, O_RDONLY)) == -1) {
  271.     return NULL;
  272.     }
  273.  
  274.     if (read(fd, (char *) lbuf, 2) != 2
  275.     || lbuf[0] != '#' || lbuf[1] != '!'
  276.     || read(fd, (char *) lbuf, HACKBUFSZ) <= 0) {
  277.     close(fd);
  278.     return NULL;
  279.     }
  280.  
  281.     close(fd);
  282.  
  283.     ws = NULL;            /* word started = 0 */
  284.  
  285.     for (p = lbuf; p < &lbuf[HACKBUFSZ];) {
  286.     switch (*p) {
  287.     case ' ':
  288.     case '\t':
  289. #ifdef NEW_CRLF
  290.     case '\r':
  291. #endif /*NEW_CRLF */
  292.         if (ws) {        /* a blank after a word.. save it */
  293.         *p = '\0';
  294. #ifndef WIN32
  295.         if (sargc < HACKVECSZ - 1) {
  296.             sargv[sargc++] = ws;
  297.         }
  298.         ws = NULL;
  299. #else /* WIN32 */
  300.         if (sargc < HACKVECSZ - 1) {
  301.             sargv[sargc] = first_word ? NULL : hb_subst(ws);
  302.             if (sargv[sargc] == NULL) {
  303.             sargv[sargc] = ws;
  304.             }
  305.             sargc++;
  306.         }
  307.         ws = NULL;
  308.         fw = 1;
  309.         first_word = 1;
  310. #endif /* WIN32 */
  311.         }
  312.         p++;
  313.         continue;
  314.  
  315.     case '\0':        /* Whoa!! what the hell happened */
  316.         return NULL;
  317.  
  318.     case '\n':        /* The end of the line. */
  319.         if (
  320. #ifdef WIN32
  321.            fw ||
  322. #endif /* WIN32 */
  323.            ws) {    /* terminate the last word */
  324.         *p = '\0';
  325. #ifndef WIN32
  326.         if (sargc < HACKVECSZ - 1) {
  327.             sargv[sargc++] = ws;
  328.         }
  329. #else /* WIN32 */
  330.         if (sargc < HACKVECSZ - 1) {    /* deal with the 1-word case */
  331.             sargv[sargc] = first_word ? NULL : hb_subst(ws);
  332.             if (sargv[sargc] == NULL) {
  333.             sargv[sargc] = ws;
  334.             }
  335.             sargc++;
  336.         }
  337. #endif /* !WIN32 */
  338.         sargv[sargc] = NULL;
  339.         }
  340.         /* Count number of entries in the old argv vector */
  341.         for (i = 0; argv[i] != NULL; ++i) {
  342.         continue;
  343.         }
  344.         ++i;
  345.  
  346.         newargv = (char **) malloc((p - lbuf + 1)
  347.                       + (i + sargc + 1) * sizeof(*newargv));
  348.         ws = &((char *) newargv)[(i + sargc + 1) * sizeof(*newargv)];
  349.  
  350.         /* Copy entries to allocated memory */
  351.         for (j = 0; j < sargc; ++j) {
  352.         newargv[j] = strcpy(ws, sargv[j]);
  353.         ws += strlen(ws) + 1;    /* skip trailing '\0' */
  354.         }
  355.         newargv[sargc] = filename;
  356.  
  357.         /* Append the old array. The old argv[0] is skipped. */
  358.         if (i > 1) {
  359.         memcpy(&newargv[sargc + 1], &argv[1],
  360.                        (i - 1) * sizeof(*newargv));
  361.         }
  362.     
  363.         newargv[sargc + i] = NULL;
  364.  
  365.         ws = NULL;
  366.  
  367.         return newargv;
  368.  
  369.     default:
  370.         if (!ws) {        /* Start a new word? */
  371.         ws = p;
  372.         }
  373.         p++;
  374.         break;
  375.     }
  376.     }
  377.     return NULL;
  378. }
  379. #else
  380. extern void ap_execve_is_not_here(void);
  381. void ap_execve_is_not_here(void) {}
  382. #endif /* NEED_HASHBANG_EMUL */
  383.