"Fossies" - the Fresh Open Source Software Archive

Member "cgiwrap-4.1/cgiwrap.c" (16 Jun 2008, 9616 Bytes) of package /linux/www/old/cgiwrap-4.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* 
    2  *  CGIWrap is free software; you can redistribute it and/or modify
    3  *  it under the terms of the GNU General Public License as published by
    4  *  the Free Software Foundation; either version 2 of the License, or
    5  *  (at your option) any later version.
    6  *
    7  *  CGIWrap is distributed in the hope that it will be useful,
    8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10  *  GNU General Public License for more details.
   11  *
   12  *  You should have received a copy of the GNU General Public License
   13  *  along with CGIWrap; if not, write to the Free Software
   14  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   15  *
   16  *  Copyright 2003-2005, Nathan Neulinger <nneul@neulinger.org>
   17  *
   18  */
   19 
   20 /**
   21  **  File: cgiwrap.c
   22  **  Purpose: Main program for cgiwrap
   23  **/ 
   24 
   25 #include "cgiwrap.h"    /* Headers for all CGIwrap source files */
   26 RCSID("$Id: cgiwrap.c 306 2008-06-13 14:02:02Z nneul $");
   27 
   28 /*
   29  * Global context structure
   30  */
   31 struct cgiwrap_context Context;
   32 
   33 /*
   34  * Main program
   35  */
   36 int main (int argc, char *argv[])
   37 {
   38     char *userStr; /* User name */
   39     char *scrStr; /* Name of script */
   40     char *scriptPath; /* Path to script file */
   41     char *cgiBaseDir; /* Base directory for cgi scripts in user's dir */
   42     struct passwd *user; /* For getting uid from name */
   43     char *interPath = NULL; /* Path to interpreter - i.e. php */
   44 #ifdef CONF_REPORT_RUSAGE
   45     pid_t childpid;
   46     struct rusage childrusage;
   47     int childstatus;
   48     char rusagemsg[1000];
   49     time_t stime;
   50     time_t etime;
   51     time_t elap_time;
   52 #endif
   53     
   54     /* Initially not a multiuser cgi script */
   55     Context.multiuser_cgi_script = 0;
   56     Context.interpreted_script = 0;
   57 
   58     /* Determine if debugging output should be done */
   59     if ( strlen(argv[0]) >= 1 )
   60     {
   61         CONF_DEBUG = !strcmp( argv[0] + strlen(argv[0]) - 1, "d");
   62         if (CONF_DEBUG)
   63         {
   64             MSG_QuietErrors = 0;
   65             MSG_HTMLMessages = 0;
   66         }
   67     }
   68 
   69     /* Output a status header if running in NoParseHeaders mode */
   70     if ( !strncmp(argv[0], "nph-", 4) )
   71     {
   72         MSG_Need_NPH_Header = 1;
   73     }
   74 #if defined(PATH_PROG_PHP)
   75     else if ( !strncmp(argv[0], "php-", 4) )
   76     {
   77         Context.interpreted_script = 1;
   78         interPath = PATH_PROG_PHP;
   79     }
   80 #endif
   81     
   82     /* Output a Content-type header if in debugging mode */
   83     if ( CONF_DEBUG )
   84     {
   85         MSG_ContentType("text/plain");
   86     }
   87 
   88     /* Initialize the log */
   89     LogInit();
   90 
   91     /* Redirect stderr to stdout */
   92 #if defined(CONF_REDIR_STDERR)
   93     DEBUG_Msg("Redirecting STDERR to STDOUT\n");
   94     if (dup2(1,2) == -1) 
   95     {
   96         MSG_Error_SystemError("Call to dup2() to redirect stderr to stdout failed!");
   97     }
   98 #endif
   99 
  100     /* Check who is running this script */
  101     VerifyExecutingUser();
  102 
  103     /* Set any default signal behavior */
  104     SetSignals();
  105 
  106     /* Set Environment Variables */
  107     SetEnvironmentVariables();
  108 
  109     /* Set CPU and other limits */
  110     SetResourceLimits();
  111 
  112     /* Output the contents of important environment variables */
  113     OutputEnvironment();
  114 
  115     /* Save copies of the original values for use later */
  116     SaveEnvironment();
  117     
  118     /* Get the user name from the given data */
  119     userStr = FetchUserString();
  120     DEBUG_Str("Retrieved User Name: ", userStr);
  121 
  122     /* Now, get whatever information that is available about that */
  123     /* user - fetch this information from the passwd file or NIS */
  124     if ( !(user = getpwnam(userStr)) )
  125     {
  126         MSG_Error_NoSuchUser(userStr);
  127     }
  128     memcpy(&Context.user, user, sizeof(struct passwd));
  129 
  130     DEBUG_Msg("\nUser Data Retrieved:");
  131     DEBUG_Str("     UserID:", user->pw_name);
  132     DEBUG_Int("        UID:", user->pw_uid);
  133     DEBUG_Int("        GID:", user->pw_gid);
  134     DEBUG_Str("   Home Dir:", user->pw_dir);
  135 
  136     /* Perform checks to make sure this user is allow to use CGI scripts */
  137     CheckUser(user); /* minuid/mingid/shell */
  138     CheckUserAccess(user); /* global config files */
  139     CheckVHostUserAccess(user); /* vhost config files */
  140 
  141     /* Determine the base directory where this user's CGI scripts
  142         are to be stored */
  143     DEBUG_Msg("");
  144     cgiBaseDir = GetBaseDirectory(user);    
  145     DEBUG_Str("Script Base Directory: ", cgiBaseDir);
  146 #if defined(CONF_MULTIUSER_CGI_DIR)
  147     DEBUG_Str("MultiUser Script Base Directory: ", CONF_MULTIUSER_CGI_DIR);
  148     if ( !DirExists(cgiBaseDir) &&
  149         !DirExists(CONF_MULTIUSER_CGI_DIR) )
  150 #else
  151     if ( !DirExists(cgiBaseDir) )
  152 #endif
  153     {
  154         MSG_Error_NoScriptDir();
  155     }
  156 
  157     /* Get the script name from the given data */
  158     DEBUG_Msg("\tFetching script string\n");
  159     scrStr = FetchScriptString(cgiBaseDir);
  160     DEBUG_Msg("\tBuilding script path\n");
  161 #ifdef CONF_MULTIUSER_CGI_DIR
  162     if ( Context.multiuser_cgi_script )
  163     {
  164         scriptPath = BuildScriptPath(CONF_MULTIUSER_CGI_DIR,scrStr);
  165     }
  166     else
  167 #endif
  168     {
  169         scriptPath = BuildScriptPath(cgiBaseDir,scrStr);
  170     }
  171 
  172     DEBUG_Msg("\tCondensing slashes.\n");
  173     Context.scriptFullPath = CondenseSlashes(scriptPath);
  174     Context.scriptRelativePath = CondenseSlashes(scrStr);
  175 
  176     DEBUG_Str("\tScript Relative Path: ", scrStr);
  177     DEBUG_Str("\tScript Absolute Path: ", scriptPath);
  178 
  179 #if defined(CONF_BLOCK_SVN_PATHS)
  180     if ( strstr(scriptPath, "/.svn/") )
  181     {
  182         MSG_Error_ExecutionNotPermitted(scriptPath, "Script is located in .svn directory.");
  183     }
  184 #endif
  185 #if defined(CONF_BLOCK_CVS_PATHS)
  186     if ( strstr(scriptPath, "/CVS/") )
  187     {
  188         MSG_Error_ExecutionNotPermitted(scriptPath, "Script is located in CVS directory.");
  189     }
  190 #endif
  191 
  192 #if defined(CONF_PHP_INTERPRETER) && defined(PATH_PROG_PHP)
  193     DEBUG_Msg("\tChecking for special interpreted script (php).");
  194     /* don't double check if already php-cgiwrap */
  195     if ( ! interPath )
  196     {
  197 
  198         if ( 
  199             StringEndsWith(scriptPath, ".php") ||
  200             StringEndsWith(scriptPath, ".php3") ||
  201             StringEndsWith(scriptPath, ".php4") ||
  202             StringEndsWith(scriptPath, ".phtml") )
  203         {
  204             Context.interpreted_script = 1;
  205             interPath = PATH_PROG_PHP;
  206         }
  207     }
  208 #endif
  209 #if defined(CONF_ERUBY_INTERPRETER) && defined(PATH_PROG_ERUBY)
  210     DEBUG_Msg("\tChecking for special interpreted script (eRuby).");
  211     if ( ! interPath )
  212     {
  213 
  214         if ( StringEndsWith(scriptPath, ".rhtml") )
  215         {
  216             Context.interpreted_script = 1;
  217             interPath = PATH_PROG_ERUBY;
  218         }
  219     }
  220 #endif
  221 #if defined(CONF_ASP_INTERPRETER) && defined(PATH_PROG_ASP)
  222     DEBUG_Msg("\tChecking for special interpreted script (asp).");
  223     if ( ! interPath )
  224     {
  225 
  226         if ( StringEndsWith(scriptPath, ".asp") )
  227         {
  228             Context.interpreted_script = 1;
  229             interPath = PATH_PROG_ASP;
  230         }
  231     }
  232 #endif
  233 
  234     if ( interPath )
  235     {
  236         DEBUG_Str("\tInterpreter Path: ", interPath);
  237     }
  238 
  239     /* Set the Correct Values of environment variables */
  240     DEBUG_Msg("\nFixing Environment Variables.");
  241     SetScriptName(userStr, scrStr);
  242     SetScriptFilename( scriptPath );
  243 #if defined(CONF_MULTIUSER_CGI_DIR)
  244     if ( Context.multiuser_cgi_script )
  245     {
  246         SetPathTranslated( CONF_MULTIUSER_CGI_DIR, scriptPath );
  247     }
  248     else
  249 #endif
  250     {
  251         SetPathTranslated( cgiBaseDir, scriptPath );
  252     }
  253 
  254     /* Output the modified environment variables */
  255     OutputEnvironment();
  256 
  257 #if !defined(CONF_REPORT_RUSAGE)
  258     /* Log the query request to the log file */
  259     Log(userStr, scrStr, "ok");
  260 #endif
  261 
  262     /* Once log is initialized, we can chroot */
  263 #if defined(CONF_CHROOT_PREFIX)
  264     DEBUG_Str("Attempting to chroot: ", CONF_CHROOT_PREFIX);
  265     if ( chdir(CONF_CHROOT_PREFIX) == -1 )
  266     {
  267         MSG_Error_SystemError("Failed to chdir for chrooting!");
  268     }
  269     if ( chroot(CONF_CHROOT_PREFIX) == -1 )
  270     {
  271         MSG_Error_SystemError("Failed to chroot!");
  272     }
  273 #endif
  274 
  275     /* Change auxilliary groups to match this user */
  276     ChangeAuxGroups(user);
  277     
  278     /* Change real and effective user and group id's to match this user */
  279     ChangeID(user);
  280 
  281     /* Change to the directory the cgi script is in */
  282     ChangeToCGIDir(scriptPath);
  283 
  284     /* Check to see if ok to execute script file */
  285     CheckScriptFile();
  286 
  287     /* Check to see if we should force handling with #! line */
  288 #if defined(CONF_PHP_NONEXEC_ONLY)
  289     if ( Context.interpreted_script && Context.script_is_executable )
  290     {
  291         DEBUG_Msg("\nScript is executable, ignoring interpreter and using #! line.");
  292         Context.interpreted_script = 0;
  293     }
  294 #endif
  295 
  296     /* Perform any AFS related tasks before executing script */
  297     Create_AFS_PAG();
  298 
  299     /* Set execPath & execArgv appropriately, depending whether an
  300        interpreter is in use. Maybe this could be moved to the PHP & ASP
  301        sections, & the interpreted_script conditional & interPath variable
  302        removed? */
  303     if (interPath && Context.interpreted_script) {
  304         Context.execPath = interPath;
  305         Context.execArgv = CreateInterpreterARGV(interPath, scrStr, argc, argv);
  306     } else {
  307         Context.execPath = scriptPath;
  308         Context.execArgv = CreateARGV(scrStr, argc, argv);
  309     }
  310 
  311     /* If we're debugging, print the executable & argument array before
  312        calling execv. */
  313     DEBUG_Exec(Context.execPath, Context.execArgv);
  314 
  315     /* Execute the script */
  316     DEBUG_Msg("\n\n");
  317     DEBUG_Msg("Output of script follows:");
  318     DEBUG_Msg("=====================================================");
  319 
  320 #if defined(CONF_REPORT_RUSAGE) && defined(HAS_WAIT3)
  321     stime = time(NULL);
  322     childpid = fork();
  323     if ( childpid < 0 ) /* fork failed */
  324     {
  325         Log(userStr, scrStr, "fork failed");
  326         exit(1);
  327     }
  328     else if ( childpid == 0 )
  329     {
  330         execv(Context.execPath, Context.execArgv);
  331         MSG_Error_ExecFailed();
  332         Log(userStr, scrStr, "failed execv of script");
  333         exit(1);
  334     }
  335     else /* fork ok */
  336     {
  337         wait3(&childstatus, 0, &childrusage);
  338         etime = time(NULL);
  339         elap_time = etime-stime;
  340         sprintf(rusagemsg, 
  341             "status=%d wtime='%lds' utime='%ds %dus' stime='%ds %dus'",
  342             WEXITSTATUS(childstatus), 
  343             elap_time,
  344             (int) childrusage.ru_utime.tv_sec, 
  345             (int) childrusage.ru_utime.tv_usec,
  346             (int) childrusage.ru_stime.tv_sec, 
  347             (int) childrusage.ru_stime.tv_usec);
  348         Log(userStr, scrStr, rusagemsg);
  349         exit(WEXITSTATUS(childstatus));
  350     }
  351 #else
  352     execv(Context.execPath, Context.execArgv);
  353     MSG_Error_ExecFailed();
  354     exit(1);
  355 #endif
  356 }