"Fossies" - the Fresh Open Source Software Archive

Member "cgiwrap-4.1/util.c" (16 Jun 2008, 35317 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: util.c
   22  **  Purpose: Various utility routines used by cgiwrap
   23  **/ 
   24 
   25 #include "cgiwrap.h"    /* Headers for all CGIwrap source files */
   26 RCSID("$Id: util.c 306 2008-06-13 14:02:02Z nneul $");
   27 
   28 /*
   29  * Encode string to protect against cross-site scripting, but only
   30  * encode if we are outputting in HTML. Otherwise send as is so that
   31  * error message shows up as transmitted.
   32  *
   33  * Strings is returned in malloced space, but should be treated as if
   34  * it was allocated staticly.
   35  */
   36 char *HTMLEncode(char *what)
   37 {
   38     static char *res = NULL;
   39     static int len = 0;
   40     int i,j;
   41 
   42     /* passed a null string, so return same */
   43     if ( !what )
   44     {
   45         return NULL;    
   46     }
   47 
   48     /* if we are in plaintext mode, just return string as is */
   49     if ( ! MSG_HTMLMessages )
   50     {
   51         return what;
   52     }
   53 
   54     /* deallocate previous mem if not sufficient for current string */
   55     /* largest encoding is &amp; so *5 should be sufficient. */
   56     if ( res && ((strlen(what)*5+1) > len) )
   57     {
   58         free(res);
   59         res = NULL;
   60         len = 0;
   61     }
   62 
   63     /* allocate mem */
   64     if ( ! res )
   65     {
   66         /* default to HUGE_STRING_LEN to eliminate excess mallocing */
   67         len = (strlen(what)*5+1);
   68         if ( len < HUGE_STRING_LEN )
   69         {
   70             len = HUGE_STRING_LEN;
   71         }
   72         res = SafeMalloc(len, "SafeEncode");
   73     }
   74 
   75     /* copy string to result, encoding as we go */
   76     j = 0;
   77     for ( i = 0; i<=strlen(what); i++ )
   78     {
   79         if ( what[i] == '<' )
   80         {
   81             res[j++] = '&';
   82             res[j++] = 'l';
   83             res[j++] = 't';
   84             res[j++] = ';';
   85         }
   86         else if ( what[i] == '>' )
   87         {
   88             res[j++] = '&';
   89             res[j++] = 'g';
   90             res[j++] = 't';
   91             res[j++] = ';';
   92         }
   93         else if ( what[i] == '&' )
   94         {
   95             res[j++] = '&';
   96             res[j++] = 'a';
   97             res[j++] = 'm';
   98             res[j++] = 'p';
   99             res[j++] = ';';
  100         }
  101         else
  102         {
  103             res[j++] = what[i];
  104         }
  105     }
  106     res[j] = '\0';
  107 
  108     return res;
  109 }
  110 
  111 /*
  112  * Safe malloc
  113  */
  114 char *SafeMalloc(size_t size, char *what)
  115 {
  116     char *tmp;
  117     
  118     tmp = (char *) malloc( size );
  119     if ( !tmp )
  120     {
  121         char msg[500];
  122         sprintf(msg, "Couldn't malloc() (%d) bytes for (%s).\n",
  123             size, what);
  124         MSG_Error_SystemError(msg);
  125     }
  126     return tmp;
  127 }
  128 
  129 /*
  130  * Safe putenv
  131  */
  132 void SafePutenv(char * string, char *what)
  133 {
  134     if (putenv(string) != 0) 
  135     {
  136         char msg[500];
  137         sprintf(msg, "Malloc failure caused putenv() failure for (%s).\n", what);
  138         MSG_Error_SystemError(msg);
  139     }
  140 }
  141 
  142 /*
  143  * Build the ARGV array for passing to the called script
  144  */
  145 char **CreateARGV( char *scrStr, int argc, char *argv[])
  146 {
  147     char **temp;
  148     int i;
  149 
  150     temp = (char **) SafeMalloc( (argc+1) * sizeof(char *), "ARGV array");
  151     
  152     temp[0] = StripPathComponents( CountSubDirs(scrStr) - 1, scrStr );
  153     temp[argc] = 0;
  154 
  155     for (i=1; i<argc; i++)
  156     {
  157         temp[i] = argv[i];
  158     }
  159 
  160     return temp;
  161 }
  162 
  163 
  164 /*
  165  * Build the ARGV array for passing to the called script via interpreter
  166  */
  167 char **CreateInterpreterARGV( char *interp, char *scrStr, int argc, char *argv[])
  168 {
  169     char **temp;
  170     int i, cnt;
  171 
  172     temp = (char **) SafeMalloc( (argc+2) * sizeof(char *), "ARGV array");
  173 
  174     temp[0] = interp;
  175 
  176     cnt = CountSubDirs(scrStr);
  177     if ( cnt < 1 )
  178     {
  179         temp[1] = scrStr;
  180     }
  181     else
  182     {
  183         char *newpath = StripPathComponents( cnt, scrStr );
  184         if ( newpath[0] == '/' )
  185         {
  186             temp[1] = newpath + 1;
  187         }
  188         else
  189         {
  190             temp[1] = newpath;
  191         }
  192     }
  193     temp[argc+1] = 0;
  194 
  195     for (i=1; i<argc; i++)
  196     {
  197         temp[i+1] = argv[i];
  198     }
  199 
  200     return temp;
  201 }
  202 
  203 
  204 /*
  205  *   Extract and return the value portion of a key=value pair found in a string
  206  */
  207 char *GetValue( char *keyword, char *string )
  208 {
  209     char *returnStr;
  210     char *dataStr;
  211     char *tempStr;
  212     char *theString;
  213 
  214     theString = strdup(string);
  215 
  216     returnStr = (char *) 0;
  217     tempStr = (char *) strtok(theString, "&");
  218     while (tempStr)
  219     {
  220         dataStr = (char *) strstr(tempStr, keyword);
  221         if ( dataStr == tempStr )
  222         {
  223             returnStr = (char *) strchr (dataStr, '=');
  224             if ( returnStr) returnStr++;
  225             tempStr = (char *) 0;
  226         }
  227         else
  228         {
  229             tempStr = (char *) strtok( (char *) 0, "&");
  230         }
  231     }
  232 
  233     if ( returnStr )
  234     {
  235         returnStr = strdup(returnStr);
  236     }
  237     free(theString);
  238     return returnStr;
  239 }
  240 
  241 /*
  242  * Check if a script name ends with a particular string (i.e. .php)
  243  */
  244 int StringEndsWith(char *string, char *ending)
  245 {
  246     int len = strlen(string);
  247     int elen = strlen(ending);
  248 
  249     if ( len >= elen && !strncmp(string + len - elen, ending, elen) )
  250     {
  251         return 1;
  252     }
  253     else
  254     {
  255         return 0;
  256     }
  257 }
  258 
  259 /*
  260  * Check if a path is safe to use
  261  *   Return true if 'path' contains any whitespace or non-printables
  262  *   Return true if 'path' contains '../'
  263  */
  264 int CheckPath(char *path)
  265 {
  266     int i,c;
  267 
  268 #if defined(CONF_STRICT_NAMES)
  269     for (i=0; i< strlen(path); i++)
  270     {
  271         c = path[i];
  272         if ( !isprint(c) || isspace(c) )
  273         {
  274             return 1;
  275         }
  276     }
  277 #endif
  278 
  279     return ( strstr(path, "../") != NULL );
  280 }
  281 
  282 /*
  283  * Condense slashes, removing duplicates and trailers
  284  */
  285 char *CondenseSlashes(char *path)
  286 {
  287     char *tmp;
  288     int i,j;
  289 
  290     tmp = (char *) SafeMalloc( strlen(path)+1, "CondenseSlashes");
  291 
  292     for (i=0, j=0; i<strlen(path); i++)
  293     {
  294         if ( !((path[i] == '/') &&
  295             ((path[i+1] == '/') || (path[i+1] == '\0')) ))
  296         {
  297             tmp[j++] = path[i];
  298         }
  299     }
  300     tmp[j] = 0;
  301 
  302     return tmp;
  303 }
  304 
  305 /*
  306  * Count the number of /'s in a string
  307  */
  308 int CountSubDirs(char *path)
  309 {
  310     int i, count;
  311     count = 0;
  312 
  313     for (i=0; i<strlen(path); i++)
  314     {
  315         if ( path[i] == '/' )
  316         {
  317             count++;
  318         }
  319     }
  320     return count;
  321 }
  322 
  323 
  324 
  325 
  326 
  327 /*
  328  * Output the contents of several important environment variables
  329  */
  330 void OutputEnvironment(void)
  331 {
  332     DEBUG_Msg("");
  333     DEBUG_Msg("Environment Variables:");  
  334     DEBUG_Str("     QUERY_STRING:", (char *) getenv("QUERY_STRING") );
  335         DEBUG_Str("      SCRIPT_NAME:", (char *) getenv("SCRIPT_NAME") );
  336         DEBUG_Str("  SCRIPT_FILENAME:", (char *) getenv("SCRIPT_FILENAME") );
  337         DEBUG_Str("     REDIRECT_URL:", (char *) getenv("REDIRECT_URL") );
  338         DEBUG_Str("        PATH_INFO:", (char *) getenv("PATH_INFO") );
  339         DEBUG_Str("  PATH_TRANSLATED:", (char *) getenv("PATH_TRANSLATED") );
  340         DEBUG_Str("      REMOTE_USER:", (char *) getenv("REMOTE_USER") );
  341         DEBUG_Str("      REMOTE_HOST:", (char *) getenv("REMOTE_HOST") );
  342         DEBUG_Str("      REMOTE_ADDR:", (char *) getenv("REMOTE_ADDR") );
  343 }
  344 
  345 /* 
  346  * Save a copy of the old environment variables 
  347  */
  348 void SaveEnvironment(void)
  349 {
  350     char *c;
  351 
  352     c = getenv("PATH_INFO");
  353     if ( c )
  354     {
  355         Context.origPathInfo = strdup(c);
  356     }
  357 }
  358 
  359 /*
  360  * Change to the users cgi-bin directory, this serves to provide
  361  * a consistent strting point for paths.
  362  */
  363 void ChangeToCGIDir(char *scriptPath)
  364 {
  365     char *tempdir;
  366     char *tempstring;
  367     int i;
  368 
  369     i = CountSubDirs(scriptPath) - 1;
  370     tempdir = GetPathComponents(i, scriptPath);
  371 
  372     tempstring = (char *) SafeMalloc (strlen(tempdir) + 5,
  373         "cgi directory path");
  374     tempstring[0] = '/';
  375     tempstring[1] = 0;
  376     strcat(tempstring, tempdir);
  377 
  378     DEBUG_Str("\nChanging current directory to", tempstring);
  379     if (chdir(tempstring) == -1) 
  380     {
  381         MSG_Error_SystemError("Cannot change to user's CGI directory via chdir()!");
  382     }
  383 
  384     free(tempdir);
  385     free(tempstring);
  386 }
  387 
  388 /*
  389  * Perform checks on the userid (global checks)
  390  */
  391 void CheckUser(struct passwd *user)
  392 {
  393 #if defined(CONF_CHECKHOST)
  394     DEBUG_Msg("Checking remote host information.");
  395     if ( ( !getenv("REMOTE_ADDR") ) || (getenv("REMOTE_ADDR")[0] == '\0') )
  396     {
  397         Log(user->pw_name, "-", "no remote host");
  398         MSG_Error_General("Cannot determine if your host is allowed to run this script.");
  399     }
  400 #endif
  401 
  402 
  403 #if defined(CONF_MINIMUM_UID)
  404     DEBUG_Msg("Checking user minimum uid.");
  405     if ( user->pw_uid < CONF_MINIMUM_UID )
  406     {
  407         Log(user->pw_name, "-", "uid less than minimum");
  408         MSG_Error_AccessControl("UID of script userid less than configured minimum.",
  409             NULL, NULL);
  410     }
  411 #endif
  412 
  413 #if defined(CONF_MINIMUM_GID)
  414     DEBUG_Msg("Checking user minimum gid.");
  415     if ( user->pw_gid < CONF_MINIMUM_GID )
  416     {
  417         Log(user->pw_name, "-", "gid less than minimum");
  418         MSG_Error_AccessControl("GID of script userid less than configured minimum.",
  419             NULL, NULL);
  420     }
  421 #endif
  422 
  423 #if defined(CONF_CHECKSHELL)
  424     {
  425     char *sh, *getusershell();
  426     int found = 0;
  427 
  428     DEBUG_Msg("Checking user shell.");
  429     while ( (sh = getusershell()) )
  430     {
  431         if (0 == strcmp( sh, user->pw_shell ))
  432         {
  433             found = 1;
  434             break;
  435         }
  436     }
  437     if (found == 0)
  438     {
  439       Log(user->pw_name, "-", "restricted login shell");
  440       MSG_Error_AccessControl("Restricted login shell, permission denied.",
  441         NULL, NULL);
  442     }
  443     }
  444 #endif
  445 
  446 #if defined(CONF_REQUIRE_REDIRECT_URL)
  447     DEBUG_Msg("Checking for required REDIRECT_URL.");
  448     if ( ( !getenv("REDIRECT_URL") ) || (getenv("REDIRECT_URL")[0] == '\0') )
  449     {
  450         Log(user->pw_name, "-", "no redirect url");
  451         MSG_Error_AccessControl("REDIRECT_URL not in environment, cgiwrap not invoked via Action/Handler.",
  452             NULL, NULL);
  453     }
  454 #endif
  455 
  456 #if defined(CONF_ENV_REQUIRE_USER)
  457     DEBUG_Msg("Checking for CGIWRAP_REQUIRE_USER in environment.");
  458     if ( getenv("CGIWRAP_REQUIRE_USER") )
  459     {
  460         if ( strcmp(getenv("CGIWRAP_REQUIRE_USER"), user->pw_name) )
  461         {
  462             Log(user->pw_name, "-", "CGIWRAP_REQUIRE_USER mismatch");
  463             MSG_Error_AccessControl("User does not match CGIWRAP_REQUIRE_USER in environment.",
  464                 NULL, NULL);
  465         }
  466     }
  467 #endif
  468 
  469 }
  470 
  471 
  472 /*
  473  * Perform checks on the userid (global checks)
  474  */
  475 void CheckUserAccess(struct passwd *user)
  476 {
  477 #if defined(CONF_DENYFILE) || defined(CONF_ALLOWFILE)
  478     char *denyfile = NULL;
  479     char *allowfile = NULL;
  480     
  481 #if defined(CONF_DENYFILE)
  482     denyfile = CONF_DENYFILE;
  483     DEBUG_Str("Global Deny File: ", denyfile);
  484 #endif
  485 #if defined(CONF_ALLOWFILE)
  486     allowfile = CONF_ALLOWFILE;
  487     DEBUG_Str("Global Allow File: ", allowfile);
  488 #endif
  489 
  490     CheckAccess_Helper(user, allowfile, denyfile);
  491 #endif
  492 }
  493 
  494 /*
  495  * Build paths of the vhost access control files, and check to
  496  * see if they allow this access. If not found, fail. 
  497  */
  498 void CheckVHostUserAccess(struct passwd *user)
  499 {
  500 #if defined(CONF_VHOST_ALLOWDIR) || defined(CONF_VHOST_DENYDIR)
  501     char *denyfile = NULL;
  502     char *allowfile = NULL;
  503     char *http_host = getenv("HTTP_HOST");
  504     char *lower_http_host = NULL;
  505     int i;
  506 
  507 #ifdef CONF_VHOST_OVERRIDE
  508     char *cgiwrap_auth_vhost = getenv("CGIWRAP_AUTH_VHOST");
  509 
  510     if ( cgiwrap_auth_vhost && cgiwrap_auth_vhost[0])
  511     {
  512         DEBUG_Str("Overriding Access Control Virtual Host: ", HTMLEncode(cgiwrap_auth_vhost));
  513         http_host = cgiwrap_auth_vhost;
  514     }
  515 #endif
  516 
  517     /* Get the vhost we are running on */
  518     if ( ! http_host || ! http_host[0] )
  519     {
  520         MSG_Error_AccessControl(
  521             "Cannot determine virtual host for access control.", NULL, NULL);
  522     }
  523     
  524     /* Force to all lowercase */
  525     DEBUG_Msg("Determining virtual host for access control.");
  526     lower_http_host = (char *) SafeMalloc(strlen(http_host) + 1,
  527         "lower_http_host");
  528     for (i=0; i<=strlen(http_host); i++)
  529     {
  530         lower_http_host[i] = tolower(http_host[i]);
  531     }
  532 
  533     DEBUG_Msg("\n");
  534     DEBUG_Str("Access Control Virtual Host: ", lower_http_host);
  535 
  536     /* Now build the two filenames */   
  537 #if defined(CONF_VHOST_ALLOWDIR)
  538     allowfile = (char *) SafeMalloc(strlen(CONF_VHOST_ALLOWDIR) + 1 +
  539         strlen(lower_http_host) + 1, "vhost allowfile");
  540     strcpy(allowfile, CONF_VHOST_ALLOWDIR);
  541     strcat(allowfile, "/");
  542     strcat(allowfile, lower_http_host);
  543 
  544     DEBUG_Str("     VHost Allow File: ", allowfile);
  545 #endif
  546 
  547 #if defined(CONF_VHOST_DENYDIR)
  548     denyfile = (char *) SafeMalloc(strlen(CONF_VHOST_DENYDIR) + 1 +
  549         strlen(lower_http_host) + 1, "vhost denyfile");
  550     strcpy(denyfile, CONF_VHOST_DENYDIR);
  551     strcat(denyfile, "/");
  552     strcat(denyfile, lower_http_host);
  553 
  554     DEBUG_Str("     VHost Deny File: ", denyfile);
  555 #endif
  556 
  557     CheckAccess_Helper(user, allowfile, denyfile);
  558     
  559     /* Clean up */
  560     if ( denyfile ) free(denyfile);
  561     if ( allowfile ) free(allowfile);
  562     free(lower_http_host);
  563 #endif
  564 }
  565 
  566 void CheckAccess_Helper(struct passwd *user, char *allowfile, char *denyfile)
  567 {
  568     int deny_exists=0, allow_exists=0;
  569     int in_deny=0, in_allow=0;  
  570 
  571     /* If neither specified, we're not configured for it */
  572     if ( !allowfile && !denyfile )
  573     {
  574         return;
  575     }
  576 
  577     DEBUG_Msg("\nChecking Access Files:");
  578 
  579     if ( denyfile )
  580     {
  581         deny_exists = FileExists(denyfile);
  582         if ( deny_exists )
  583         {
  584             DEBUG_Str("  Deny file exists: ", denyfile);
  585         }
  586     }
  587     if ( allowfile )
  588     {
  589         allow_exists = FileExists(allowfile);
  590         if ( allow_exists )
  591         {
  592             DEBUG_Str("  Allow file exists: ", allowfile);
  593         }
  594     }
  595 
  596     if ( !deny_exists && !allow_exists )
  597     {
  598         Log(user->pw_name, "-", "access control files not found");
  599         MSG_Error_AccessControl("Access control files not found!",
  600             allowfile, denyfile);
  601     }
  602 
  603     if ( deny_exists )
  604     {
  605             DEBUG_Str("  Checking deny file for",user->pw_name);
  606         in_deny = UserInFile(denyfile, user->pw_name);
  607     }
  608     if ( allow_exists )
  609     {
  610             DEBUG_Str("  Checking allow file for",user->pw_name);
  611         in_allow = UserInFile(allowfile, user->pw_name);
  612     }
  613 
  614     if ( (in_allow && in_deny) ||
  615         ( allow_exists && !in_allow ) ||
  616         ( deny_exists && in_deny ) )
  617     {
  618         Log(user->pw_name, "-", "user/host not permitted");
  619         MSG_Error_AccessControl(
  620             "Script userid and/or remote host not permitted!",
  621             NULL, NULL);
  622     }
  623 }
  624 
  625 
  626 /*
  627  * Perform file checks on the script file
  628  */
  629 void CheckScriptFile(void)
  630 {
  631     struct stat fileStat; /* For checking file status */
  632     struct stat fileLStat; /* For checking symlink status */
  633 
  634     if ( CheckPath(Context.scriptFullPath) )
  635     {
  636         MSG_Error_ExecutionNotPermitted(Context.scriptFullPath,
  637             "Script path contains illegal components");
  638     }
  639     
  640 #if !defined(CONF_SUBDIRS)
  641     /* Check if script is in a subdirectory */
  642     if ( CountSubDirs(Context.scriptRelativePath) > 0 )
  643     {
  644         Log(Context.user.pw_name, Context.scriptFullPath, 
  645             "script in subdir not allowed");
  646         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  647             "Scripts in subdirectories are not allowed");
  648     }
  649 #endif
  650 
  651     if ( stat(Context.scriptFullPath, &fileStat) )
  652     {
  653         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  654             "Script file not found.");
  655     }
  656 
  657     if ( lstat(Context.scriptFullPath, &fileLStat) )
  658     {
  659         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  660             "Script file not found.");
  661     }
  662 
  663 #if defined(CONF_CHECK_SYMLINK)
  664     if ( S_ISLNK(fileLStat.st_mode) )
  665     {
  666         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  667             "Script is a symbolic link");
  668     }
  669 #endif      
  670 
  671     if ( !S_ISREG(fileStat.st_mode) )
  672     {
  673         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  674             "Script is not a regular file");
  675     }
  676 
  677     if (fileStat.st_mode & S_IXUSR)
  678     {
  679         Context.script_is_executable = 1; /* record this in case we might use interpreter later */
  680     }
  681     else if ( !Context.interpreted_script ) /* if we're passing to interpreter, isn't an error to be non-executable */
  682     {
  683         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  684             "Script is not executable. Issue 'chmod 755 filename'");
  685     }
  686 
  687 
  688 #if defined(CONF_CHECK_SCRUID)
  689     if (!S_ISLNK(fileLStat.st_mode))
  690     {
  691         if (!Context.multiuser_cgi_script && fileStat.st_uid != Context.user.pw_uid)
  692         {
  693             MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  694                 "Script does not have same UID");
  695         }
  696     }
  697     else
  698     {
  699         if (!Context.multiuser_cgi_script && fileLStat.st_uid != Context.user.pw_uid)
  700         {
  701             MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  702                 "Symlink to script does not have same UID");
  703         }
  704     }
  705 #endif
  706 
  707 
  708 #if defined(CONF_CHECK_SCRGID)
  709     if (!Context.multiuser_cgi_script && fileStat.st_gid != Context.user.pw_gid)
  710     {
  711         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  712             "Script does not have same GID");
  713     }
  714 #endif
  715 
  716 
  717 #if defined(CONF_CHECK_SCRSUID)
  718     if (fileStat.st_mode & S_ISUID)
  719     {
  720         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  721             "Script is setuid");
  722     }
  723 #endif
  724 
  725 
  726 #if defined(CONF_CHECK_SCRSGID)
  727     if (fileStat.st_mode & S_ISGID)
  728     {
  729         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  730             "Script is setgid");
  731     }
  732 #endif
  733 
  734 #if defined(CONF_CHECK_SCRGWRITE)
  735     if (fileStat.st_mode & S_IWGRP)
  736     {
  737         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  738             "Script is group writable.");
  739     }
  740 #endif
  741 
  742 #if defined(CONF_CHECK_SCROWRITE)
  743     if (fileStat.st_mode & S_IWOTH)
  744     {
  745         MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
  746             "Script is world writable.");
  747     }
  748 #endif
  749 }
  750 
  751 
  752 /*
  753  *  Verify the CGIwrap is being executed by the server userid
  754  *  and that it is running as effective uid root.
  755  */
  756 void VerifyExecutingUser(void)
  757 {
  758 #if defined(CONF_CHECK_HTTPD_USER)
  759     struct passwd *user;
  760 
  761     if ( !(user = getpwnam(CONF_HTTPD_USER)) )
  762     {
  763         MSG_Error_ServerUserNotFound();
  764     }
  765 
  766     if ( getuid() != user->pw_uid )
  767     {
  768         MSG_Error_ServerUserMismatch();
  769     }
  770 #endif
  771 
  772     if ( geteuid() != 0 )
  773     {
  774         MSG_Error_CGIWrapNotSetUID();
  775     }
  776 }
  777 
  778 /*
  779  * Construct string containing full path to script
  780  */
  781 char *BuildScriptPath(char *basedir, char *scrStr)
  782 {
  783     char *tmp;
  784     tmp = (char *) SafeMalloc ( strlen(basedir) + strlen(scrStr) + 5,
  785         "scriptPath");
  786 
  787     sprintf(tmp, "%s/%s", basedir, scrStr);
  788     return tmp;
  789 }
  790 
  791 
  792 /*
  793  * Extract the first 'count' components of 'path'
  794  */
  795 char *GetPathComponents(int count, char *path)
  796 {
  797     char *tmp;
  798     int i, j, found;
  799     int done;
  800     int len;
  801 
  802     tmp = strdup(path); 
  803     len = strlen(tmp);
  804 
  805     /* First skip over any leading /'s */
  806     i = 0;
  807     done = 0;
  808     while ( i<len && !done )
  809     {
  810         if ( path[i] == '/' )
  811         {
  812             i++;
  813         }
  814         else
  815         {
  816             done = 1;
  817         }
  818     }
  819 
  820     
  821     /* Now, only copy a certain number of components */
  822     j = 0;
  823     found = 0;
  824     while ( i<len && found < count)
  825     {
  826         if ( path[i] == '/' )
  827         {
  828             found++;
  829         }   
  830         if ( found < count )
  831         {
  832             tmp[j] = path[i];
  833             j++;
  834         }
  835         i++;
  836     }
  837     tmp[j] = 0;     
  838 
  839     return tmp;
  840 }
  841 
  842 
  843 
  844 /*
  845  * Extract all but the first 'count' components of 'path'
  846  */
  847 char *StripPathComponents(int count, char *path)
  848 {
  849     char *tmp;
  850     int i, found;
  851     int done;
  852     int len;
  853 
  854     len = strlen(path);
  855 
  856     /* First skip over any leading /'s */
  857     i = 0;
  858     done = 0;
  859     while ( i<len && !done )
  860     {
  861         if ( path[i] == '/' )
  862         {
  863             i++;
  864         }
  865         else
  866         {
  867             done = 1;
  868         }
  869     }
  870 
  871     
  872     /* Now, skip over a certain number of components */
  873     found = 0;
  874     while ( i<len && found < count)
  875     {
  876         if ( path[i] == '/' )
  877         {
  878             found++;
  879         }   
  880         if ( found < count )
  881         {
  882             i++;
  883         }
  884     }
  885     tmp = strdup(path + i);
  886 
  887     return tmp;
  888 }
  889 
  890 
  891 /*
  892  * Set Environment Variables
  893  */
  894 void SetEnvironmentVariables(void)
  895 {
  896 #if defined(CONF_SETENV_ANY)
  897     int i;
  898     char msg[500];
  899 
  900     struct cgiwrap_setenv_table
  901     {
  902         char *variable;
  903         char *value;
  904         char *setstring;
  905     } cgiwrap_setenvs[] = {
  906 #if defined(CONF_SETENV_PATH)
  907         {"PATH", CONF_SETENV_PATH, "PATH=" CONF_SETENV_PATH},
  908 #endif
  909 #if defined(CONF_SETENV_TZ)
  910         {"TZ", CONF_SETENV_TZ, "TZ=" CONF_SETENV_TZ},
  911 #endif
  912 #if defined(CONF_SETENV_LD_LIBRARY_PATH)
  913         {"LD_LIBRARY_PATH", CONF_SETENV_LD_LIBRARY_PATH, 
  914             "LD_LIBRARY_PATH=" CONF_SETENV_LD_LIBRARY_PATH},
  915 #endif
  916         {0,0,0}
  917     };
  918 
  919     for (i=0; cgiwrap_setenvs[i].variable; i++)
  920     {
  921         sprintf(msg, "Setting Environment Variable(%s) to (%s)\n", 
  922             cgiwrap_setenvs[i].variable,
  923             cgiwrap_setenvs[i].value);
  924         DEBUG_Msg(msg);
  925 
  926 #if defined(HAS_PUTENV)
  927         SafePutenv(cgiwrap_setenvs[i].setstring, 
  928             "set environment variable");
  929 #endif
  930     }
  931 #endif
  932 }
  933 
  934 
  935 /*
  936  * Set Resource Limits
  937  */
  938 void SetResourceLimits(void)
  939 {
  940 #if defined(CONF_USE_RLIMIT_ANY)
  941     struct rlimit limstruct;
  942     int i;
  943     char msg[200];
  944 
  945     struct cgiwrap_rlimit_table
  946     {
  947         int which;
  948         char *label;
  949         long value;
  950     } cgiwrap_rlimits[] = {
  951 #if defined(CONF_USE_RLIMIT_CPU) && defined(RLIMIT_CPU)
  952         {RLIMIT_CPU, "cpu time", CONF_USE_RLIMIT_CPU},
  953 #endif
  954 #if defined(CONF_USE_RLIMIT_VMEM) && defined(RLIMIT_VMEM)
  955         {RLIMIT_VMEM, "virtual memory", CONF_USE_RLIMIT_VMEM},
  956 #endif
  957 #if defined(CONF_USE_RLIMIT_FSIZE) && defined(RLIMIT_FSIZE)
  958         {RLIMIT_FSIZE, "writable file size", CONF_USE_RLIMIT_FSIZE},
  959 #endif
  960 #if defined(CONF_USE_RLIMIT_DATA) && defined(RLIMIT_DATA)
  961         {RLIMIT_DATA, "data size", CONF_USE_RLIMIT_DATA},
  962 #endif
  963 #if defined(CONF_USE_RLIMIT_STACK) && defined(RLIMIT_STACK)
  964         {RLIMIT_STACK, "stack size", CONF_USE_RLIMIT_STACK},
  965 #endif
  966 #if defined(CONF_USE_RLIMIT_AS) && defined(RLIMIT_AS)
  967         {RLIMIT_AS, "total available memory", CONF_USE_RLIMIT_AS},
  968 #endif
  969 #if defined(CONF_USE_RLIMIT_CORE) && defined(RLIMIT_CORE)
  970         {RLIMIT_CORE, "core file size", CONF_USE_RLIMIT_CORE},
  971 #endif
  972 #if defined(CONF_USE_RLIMIT_RSS) && defined(RLIMIT_RSS)
  973         {RLIMIT_RSS, "resident set size", CONF_USE_RLIMIT_RSS},
  974 #endif
  975 #if defined(CONF_USE_RLIMIT_NPROC) && defined(RLIMIT_NPROC)
  976         {RLIMIT_NPROC, "number of processes", CONF_USE_RLIMIT_NPROC},
  977 #endif
  978 #if defined(CONF_USE_RLIMIT_NOFILE) && defined(RLIMIT_NOFILE)
  979         {RLIMIT_NOFILE, "number of open files", CONF_USE_RLIMIT_NOFILE},
  980 #endif
  981 #if defined(CONF_USE_RLIMIT_MEMLOCK) && defined(RLIMIT_MEMLOCK)
  982         {RLIMIT_MEMLOCK, "lockable memory", CONF_USE_RLIMIT_MEMLOCK},
  983 #endif
  984         {0,0,0}
  985     };
  986 
  987     for (i=0; cgiwrap_rlimits[i].label; i++)
  988     {
  989         limstruct.rlim_cur = cgiwrap_rlimits[i].value;
  990 
  991 #if defined(CONF_SOFT_RLIMIT_ONLY)
  992         limstruct.rlim_max = RLIM_INFINITY;
  993 #else
  994         limstruct.rlim_max = cgiwrap_rlimits[i].value;
  995 #endif
  996 
  997         sprintf(msg, "Limiting (%s) to (%ld)\n", 
  998             cgiwrap_rlimits[i].label,
  999             cgiwrap_rlimits[i].value);
 1000         DEBUG_Msg(msg);
 1001 
 1002         setrlimit(cgiwrap_rlimits[i].which, &limstruct);
 1003     }
 1004 #endif
 1005 }
 1006 
 1007 
 1008 /*
 1009  * Set default signal behavior
 1010  */
 1011 void SetSignals(void)
 1012 {
 1013 #if defined(SIGXCPU) && defined(HAS_SIGSET)
 1014     DEBUG_Msg("Setting SIGXCPU to default behaviour\n");
 1015     sigset(SIGXCPU, SIG_DFL);
 1016 #elif defined(SIGXCPU)
 1017     struct sigaction default_action;
 1018     default_action.sa_handler = SIG_DFL;
 1019     default_action.sa_flags = 0;
 1020     DEBUG_Msg("Setting SIGXCPU to default behaviour\n");
 1021     sigaction(SIGXCPU, &default_action, NULL);
 1022 #endif
 1023 }
 1024 
 1025 
 1026 /*
 1027  * Change real and effective UID and GID to those of 'user'
 1028  */
 1029 void ChangeID ( struct passwd *user)
 1030 {
 1031 
 1032 
 1033 #if defined(HAS_SETGID) && defined(HAS_SETUID)
 1034     setgid( user->pw_gid );
 1035     setuid( user->pw_uid );
 1036 #elif defined(HAS_SETRESGID) && defined(HAS_SETRESUID)
 1037     setresgid( user->pw_gid, user->pw_gid, user->pw_gid );
 1038     setresuid( user->pw_uid, user->pw_uid, user->pw_uid );
 1039 #elif defined(HAS_SETREGID) && defined(HAS_SETREUID)
 1040     setregid( user->pw_gid, user->pw_gid );
 1041     setreuid( user->pw_uid, user->pw_uid );
 1042 #elif defined(HAS_SETEGID) && defined(HAS_SETEUID) && defined(HAS_SETRGID) && defined(HAS_SETRUID)
 1043     setegid( user->pw_gid );
 1044     setrgid( user->pw_gid );
 1045     seteuid( user->pw_uid );
 1046     setruid( user->pw_uid );
 1047 #else
 1048 #error "Configuration Error, No Way to Change IDs"
 1049 #endif
 1050 
 1051 
 1052     DEBUG_Msg("\nUIDs/GIDs Changed To:");
 1053     DEBUG_Int("   RUID:", getuid());
 1054     DEBUG_Int("   EUID:", geteuid());
 1055     DEBUG_Int("   RGID:", getgid());
 1056     DEBUG_Int("   EGID:", getegid());
 1057 
 1058 
 1059     /***/
 1060     /**   Check if ID's were actually changed */
 1061     /***/
 1062     if ( getuid() != user->pw_uid )
 1063     {
 1064         MSG_Error_General("Real UID could not be changed!");
 1065     }
 1066     if ( geteuid() != user->pw_uid )
 1067     {
 1068         MSG_Error_General("Effective UID could not be changed!");
 1069     }
 1070     if ( getgid() != user->pw_gid )
 1071     {
 1072         MSG_Error_General("Real GID could not be changed!");
 1073     }
 1074     if ( getegid() != user->pw_gid )
 1075     {
 1076         MSG_Error_General("Effective GID could not be changed!");
 1077     }
 1078 }
 1079 
 1080 /*
 1081  * Set the process's auxilliary groups
 1082  */
 1083 void ChangeAuxGroups(struct passwd *user)
 1084 {
 1085 #if defined(CONF_MINIMUM_GID) && defined(HAS_GETGROUPS)
 1086     int i,j;
 1087     gid_t *groups;
 1088 #endif
 1089 
 1090 #if defined(HAS_SETGROUPS) && defined(CONF_SETGROUPS)
 1091     gid_t grouplist[1];
 1092     grouplist[0] = user->pw_gid;
 1093 
 1094     if ( setgroups(1, grouplist) == -1 )
 1095         MSG_Error_SystemError("setgroups() failed!");
 1096 #endif
 1097 
 1098 #if defined(HAS_INITGROUPS) && defined(CONF_INITGROUPS)
 1099     if ( initgroups( user->pw_name, user->pw_gid ) == -1 )
 1100         MSG_Error_SystemError("initgroups() failed!");
 1101 #endif
 1102 
 1103     /* verify here that we didn't enable a group less than minimum */
 1104 #if defined(CONF_MINIMUM_GID) && defined(HAS_GETGROUPS)
 1105     i = getgroups(0, groups);
 1106     if ( i > 0 )
 1107     {
 1108         groups = (gid_t *)SafeMalloc(i * sizeof(gid_t), "Auxilliary Group List");
 1109         getgroups(i, groups);
 1110 
 1111         for ( j=0; j<i; j++ )
 1112         {
 1113             if ( groups[j] < CONF_MINIMUM_GID )
 1114             {
 1115                         Log(user->pw_name, "-", "supplementary gid less than minimum");
 1116                         MSG_Error_AccessControl(
 1117                     "Supplementary GID of script userid less than configured minimum.",
 1118                     NULL, NULL);
 1119             }
 1120         }
 1121     }
 1122 #endif
 1123 }
 1124 
 1125 
 1126 /*
 1127  * Return true if 'user' is listed in file 'filename'
 1128  */
 1129 int UserInFile(char *filename, char *user)
 1130 {
 1131     FILE *file;
 1132     char temp[HUGE_STRING_LEN];
 1133 #if defined(CONF_CHECKHOST)
 1134     int count, remote_addr[4],spec_mask[4],spec_addr[4];
 1135     char *i, *tmpuser;
 1136 #endif
 1137     int j, intail;
 1138 
 1139 #if defined(CONF_CHECKHOST)
 1140     if (sscanf(getenv("REMOTE_ADDR"),"%d.%d.%d.%d",
 1141         &remote_addr[0],&remote_addr[1],
 1142         &remote_addr[2],&remote_addr[3]) != 4 )
 1143     {
 1144         Log(user, "-", "no remote host");
 1145         MSG_Error_General("Your host is not allowed to run this");
 1146     }
 1147 #endif
 1148 
 1149     if ( (file=fopen(filename,"r")) == NULL )
 1150     {
 1151         MSG_Error_SystemError("Couldn't open access control file");
 1152     }
 1153 
 1154     while ( !feof(file) )
 1155     {
 1156         temp[0] = 0;
 1157         if ( !fgets(temp, HUGE_STRING_LEN, file) )
 1158         {
 1159             fclose(file);
 1160             return 0;
 1161         }
 1162         intail=1;
 1163         for (j=strlen(temp)-1; j>=0; j--)
 1164         {
 1165             if ( !isprint(temp[j]) )
 1166             {
 1167                 temp[j] = 0;
 1168             }
 1169             else 
 1170                         { 
 1171                              if (intail) 
 1172                  {
 1173                        if (isspace(temp[j]))
 1174                    {
 1175                          temp[j] = 0;
 1176                    }
 1177                    else 
 1178                    {
 1179                          intail = 0;
 1180                    }
 1181                  }
 1182             }
 1183         }
 1184 
 1185         if ( !strcmp(temp,user) )
 1186         {
 1187             fclose(file);
 1188             DEBUG_Str("    Found",user);
 1189             return 1;
 1190         }
 1191 
 1192 #if defined(CONF_ALLOWDENY_NETGROUPS) && defined(HAS_INNETGR)
 1193         if ( strlen(temp) > 3 && temp[0] == '+' && temp[1] == '@' )
 1194         {
 1195             if ( innetgr(&temp[2], NULL, user, NULL) )
 1196             {
 1197                 DEBUG_Str("    Found in netgroup ", user);
 1198                 return 1;
 1199             }
 1200         }
 1201 #elif defined(CONF_ALLOWDENY_NETGROUPS)
 1202 #error netgroup support requested, but innetgr not available
 1203 #endif
 1204 
 1205 #if defined(CONF_CHECKHOST)
 1206         i = strchr(temp, '@');
 1207         tmpuser = strtok(temp, "@");
 1208         if ( (i != NULL) && (tmpuser != NULL) &&
 1209             ( (!strcmp(tmpuser,user)) || (!strcmp(tmpuser, "*")) ) )
 1210         {
 1211             while (i != NULL)
 1212             {
 1213                 spec_mask[0]=255; 
 1214                 spec_mask[1]=255; 
 1215                 spec_mask[2]=255; 
 1216                 spec_mask[3]=255;
 1217                 i++;
 1218                 count = sscanf(i,"%d.%d.%d.%d/%d.%d.%d.%d",
 1219                     &spec_addr[0], &spec_addr[1],
 1220                     &spec_addr[2], &spec_addr[3],
 1221                     &spec_mask[0], &spec_mask[1],
 1222                     &spec_mask[2], &spec_mask[3]);
 1223 
 1224                 if (count != 4 && count != 8) {
 1225                     Log(user, "-", "incorrectly formatted allow/deny line");
 1226                     MSG_Error_General("Invalid line in access control file");
 1227                 }
 1228 
 1229                 if (((spec_mask[0] & spec_addr[0]) == (spec_mask[0] & remote_addr[0])) &&
 1230                     ((spec_mask[1] & spec_addr[1]) == (spec_mask[1] & remote_addr[1])) &&
 1231                     ((spec_mask[2] & spec_addr[2]) == (spec_mask[2] & remote_addr[2])) &&
 1232                     ((spec_mask[3] & spec_addr[3]) == (spec_mask[3] & remote_addr[3])))
 1233                 {
 1234                     fclose(file);
 1235                     return 1;
 1236                 }
 1237                 i = strchr(i,',');
 1238             }
 1239         }
 1240 #endif
 1241     }
 1242     fclose(file);
 1243 
 1244     return 0;
 1245 }
 1246 
 1247 
 1248 /*
 1249  * Initialize the logging
 1250  */
 1251 void LogInit (void)
 1252 {
 1253 #if defined(CONF_LOG_USEFILE)
 1254     FILE *logFile;
 1255     int logfd;
 1256 #endif
 1257 
 1258     DEBUG_Msg("Initializing Logging");
 1259 
 1260 #if defined(CONF_LOG_USEFILE)
 1261     logfd = open(CONF_LOG_LOGFILE, O_WRONLY | O_CREAT | O_APPEND, 
 1262         S_IRUSR | S_IWUSR);
 1263     if ( logfd == -1 )
 1264     {
 1265         MSG_Error_SystemError("Could not open log file for appending!");
 1266     }
 1267     /* set the close-on-exec flag for logfd */
 1268     if (fcntl(logfd, F_SETFD, 1) == -1) 
 1269     {
 1270         MSG_Error_SystemError("Could not set close-on-exec flag for log file!");
 1271     }
 1272 
 1273     /* open a file pointer from that file descriptor */
 1274     logFile = fdopen(logfd, "a");
 1275     if ( !logFile )
 1276     {
 1277         MSG_Error_SystemError("Could not open file stream from file descriptor!");
 1278     }
 1279 
 1280     Context.logFile = logFile;
 1281 #endif
 1282 #if defined(CONF_LOG_USESYSLOG) && defined(HAS_SYSLOG)
 1283     openlog("cgiwrap", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
 1284 #endif
 1285 }
 1286 
 1287 /*
 1288  * Add an entry to the log file
 1289  */
 1290 void Log (char *user, char *script, char *msg)
 1291 {
 1292     time_t timevar;
 1293     char *timeString;
 1294 
 1295     time(&timevar);
 1296     timeString = ctime(&timevar);
 1297 
 1298     DEBUG_Msg("");
 1299 
 1300 #if defined(CONF_LOG_USEFILE)
 1301     DEBUG_Msg("Logging Request (File)");
 1302 
 1303     fprintf(Context.logFile, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
 1304         NullCheck( user ),
 1305         NullCheck( script ),
 1306         NullCheck( getenv("REMOTE_HOST") ),
 1307         NullCheck( getenv("REMOTE_ADDR") ),
 1308         NullCheck( getenv("REMOTE_USER") ),
 1309         NullCheck( msg ),
 1310         NullCheck( timeString ) );
 1311     fflush(Context.logFile);
 1312 #endif
 1313 #if defined(CONF_LOG_USESYSLOG) && defined(HAS_SYSLOG)
 1314     DEBUG_Msg("Logging Request (syslog)");
 1315 
 1316     syslog(LOG_INFO, "[%s] %s, %s, %s, %s, %s, %s",
 1317         NullCheck( CONF_LOG_LABEL ),
 1318         NullCheck( user ), 
 1319         NullCheck( script ),
 1320         NullCheck( getenv("REMOTE_HOST") ), 
 1321         NullCheck( getenv("REMOTE_ADDR") ),
 1322         NullCheck( getenv("REMOTE_USER") ),
 1323         NullCheck( msg ) );
 1324 
 1325 /* don't want to close log at this point */
 1326 /*  closelog(); */
 1327 #endif
 1328 }
 1329 
 1330 /*
 1331  * Terminate logging
 1332  */
 1333 void LogEnd(void)
 1334 {
 1335 #if defined(CONF_LOG_USEFILE)
 1336     if ( Context.logFile )
 1337     {
 1338         fclose(Context.logFile);
 1339     }
 1340 #endif
 1341 }
 1342 
 1343 /*
 1344  * Set the correct SCRIPT_NAME environment variable
 1345  */
 1346 void SetScriptName(char *userStr, char *scrStr )
 1347 {
 1348     char *buf;
 1349     char *name;
 1350 
 1351 #if defined(CONF_USE_REDIRECT_URL)
 1352     char *redurl = getenv("REDIRECT_URL");
 1353     int len;
 1354 
 1355     /* Use REDIRECT_URL to build SCRIPT_NAME so we can
 1356      * keep the URL the way user specified them.
 1357      * For this to work we need to have already set
 1358      * the correct PATH_INFO env if needed (this is
 1359      * done by FetchScriptString).
 1360      * NOTE: REDIRECT_URL is not a CGI standard
 1361      * environment variable. --san@cobalt.rmnet.it;
 1362      */
 1363     if ( redurl )
 1364     {
 1365         name = getenv("PATH_INFO");
 1366         if ( name ) {
 1367             /* We need to strip PATH_INFO from REDIRECT_URL */
 1368             /* this code doesn't appear to be completely implemented */
 1369             len = strlen(redurl);
 1370             buf = (char*) SafeMalloc (strlen("SCRIPT_NAME=") +
 1371                     len + 2,
 1372                 "new SCRIPT_NAME environment variable");
 1373             snprintf(buf, strlen("SCRIPT_NAME=")+len+1,
 1374                 "SCRIPT_NAME=%s", redurl);
 1375             
 1376         }
 1377         else {
 1378             buf = (char*) SafeMalloc (strlen("SCRIPT_NAME=") +
 1379                     strlen(redurl) + 2,
 1380                 "new SCRIPT_NAME environment variable");
 1381             sprintf(buf, "SCRIPT_NAME=%s", redurl);
 1382         }
 1383         SafePutenv(buf, "set SCRIPT_NAME environment variable");
 1384         return;
 1385     }
 1386 #endif
 1387 
 1388 #if defined(CONF_USE_SCRIPT_URL)
 1389     name = getenv("SCRIPT_URL");
 1390     if ( name ) {
 1391         buf = (char*) SafeMalloc (strlen("SCRIPT_NAME=") + strlen(name) + 3, 
 1392             "new SCRIPT_NAME environment variable");
 1393 
 1394         sprintf(buf, "SCRIPT_NAME=%s", name);
 1395         SafePutenv(buf,"set SCRIPT_NAME environment variable");
 1396         return;
 1397     }
 1398 
 1399 #endif
 1400 
 1401     name = getenv("SCRIPT_NAME");
 1402     if ( name ) {
 1403         /* only set SCRIPT_NAME if it was already set */
 1404 
 1405         buf = (char*) SafeMalloc (strlen("SCRIPT_NAME") +
 1406             strlen(name) + strlen(userStr)
 1407             + strlen(scrStr) + 5, "new SCRIPT_NAME environment variable");
 1408 
 1409         sprintf(buf, "%s=%s/%s/%s", "SCRIPT_NAME", 
 1410             name, userStr, scrStr);
 1411         SafePutenv(buf, "set SCRIPT_NAME environment variable");
 1412     }
 1413 }
 1414 
 1415 
 1416 /*
 1417  * Set the correct SCRIPT_FILENAME environment variable (PHP uses this)
 1418  */
 1419 void SetScriptFilename (char *scriptPath) 
 1420 {
 1421     char *buf;
 1422   char *name;
 1423 
 1424     name = getenv ("SCRIPT_FILENAME");
 1425     if ( name ) {
 1426         /* only set SCRIPT_FILENAME if it was already set */
 1427 
 1428         buf = (char*) SafeMalloc (strlen("SCRIPT_FILENAME") +
 1429             + strlen(scriptPath) + 5, "new SCRIPT_FILENAME environment variable");
 1430 
 1431         sprintf(buf, "%s=%s", "SCRIPT_FILENAME", scriptPath);
 1432         SafePutenv(buf, "set SCRIPT_NAME environment variable");
 1433     }
 1434 }
 1435 
 1436 
 1437 
 1438 /*
 1439  * Set the correct PATH_TRANSLATED environment variable
 1440  */
 1441 void SetPathTranslated( char *cgiBaseDir, char *scriptPath )
 1442 {
 1443     char *buf;
 1444     char *old_pt, *new_pt;
 1445     char *old_pi, *new_pi;
 1446     char *docroot;
 1447 
 1448     old_pt = getenv("PATH_TRANSLATED");
 1449     if ( ! old_pt )
 1450     {
 1451         /* don't set one if the server didn't */
 1452         return;
 1453     }
 1454     new_pt = strdup(old_pt);
 1455 
 1456     old_pi = Context.origPathInfo;
 1457     new_pi = Context.newPathInfo;
 1458     if ( !old_pi || !new_pi )
 1459     {
 1460         /* can't match against anything */
 1461         return;
 1462     }
 1463 
 1464     /* check if we find old path_info (with user) in the path_translated string */
 1465     buf = strstr(new_pt, old_pi);
 1466     if ( buf )
 1467     {
 1468         /* if so, copy in what we determined pathinfo should be after stripping off user portion */
 1469         if ( Context.interpreted_script ) /* for PHP we do not strip script path from PATH_TRANSLATED */
 1470         {
 1471             strcpy(buf, "/");
 1472             strcat(buf, Context.scriptRelativePath);
 1473             strcat(buf, new_pi);
 1474         } else {
 1475             strcpy(buf, new_pi);
 1476         }
 1477 
 1478         buf = (char *) SafeMalloc( strlen(new_pt) + strlen("PATH_TRANSLATED") + 5, 
 1479             "new PATH_TRANSLATED environment variable");
 1480         sprintf(buf, "%s=%s", "PATH_TRANSLATED", new_pt); 
 1481         SafePutenv(buf, "new PATH_TRANSLATED environment variable");
 1482 
 1483         return;
 1484     }
 1485 
 1486     /* we might be able to fall back to using docroot if we have it */
 1487 
 1488     docroot = getenv("DOCUMENT_ROOT");
 1489     if ( docroot )
 1490     {
 1491         buf = (char *) SafeMalloc( strlen("PATH_TRANSLATED") + strlen(docroot) + 
 1492             strlen(new_pi) + 5, "new PATH_TRANSLATED environment variable");
 1493         sprintf(buf, "PATH_TRANSLATED=%s%s", docroot, new_pi);
 1494         SafePutenv(buf, "new PATH_TRANSLATED environment variable");
 1495 
 1496         return;
 1497     }
 1498 }
 1499 
 1500 
 1501 
 1502 /*
 1503  * If using AFS, create a process authentication group for this process
 1504  * This protects the server from any authentication changes that the script
 1505  * might make. It also prevents the script from inheriting the servers
 1506  * authentication if it is running authenticated
 1507  */
 1508 #if defined(CONF_AFS_SETPAG)
 1509     void setpag(void);
 1510 #endif
 1511 void Create_AFS_PAG(void)
 1512 {
 1513 #if defined(CONF_AFS_SETPAG)
 1514     DEBUG_Msg("");
 1515     DEBUG_Msg("Setting AFS Process Authentication Group (PAG)");
 1516     setpag();
 1517 #endif
 1518 }
 1519 
 1520 /*
 1521  * Rewrite user dir from configuration file if option is enabled
 1522  */
 1523 char *GetUserDir(char *user)
 1524 {
 1525 #if defined(CONF_USERDIRFILE)
 1526     FILE *file;
 1527     static char temp[500];
 1528     int i, j;
 1529 
 1530     DEBUG_Msg("\nProcessing user directory configuration file.");
 1531 
 1532     if ( (file=fopen(CONF_USERDIRFILE,"r")) == NULL )
 1533     {
 1534         MSG_Error_SystemError("Couldn't open user directory config file");
 1535     }
 1536 
 1537     temp[0]=0;
 1538     while ( !feof(file) )
 1539     {
 1540         fgets(temp, 450, file);
 1541         i = strlen(user);
 1542 
 1543         if ( !strncmp(user, temp, i) && temp[i] == ':' )
 1544         {
 1545             for ( j=0; j<strlen(temp); j++)
 1546             {
 1547                 if ( !isprint(temp[j]) )
 1548                 {
 1549                     temp[j] = 0;
 1550                 } 
 1551             }   
 1552         
 1553             fclose(file);
 1554             return &temp[i+1];
 1555         }
 1556     }
 1557     fclose(file);
 1558 #endif
 1559 
 1560     return NULL;
 1561 }
 1562 
 1563 
 1564 /*
 1565  * Determine the base directory for user's scripts
 1566  */
 1567 char *GetBaseDirectory(struct passwd *user)
 1568 {
 1569     char *userdir, *basedir;
 1570 
 1571     userdir = GetUserDir(user->pw_name);
 1572 
 1573     if ( userdir )
 1574     {
 1575         DEBUG_Msg("Using configured base directory.\n");
 1576         basedir = (char *) SafeMalloc ( strlen(userdir) + 4,
 1577             "script base directory");
 1578         strcpy(basedir, userdir);
 1579     }
 1580     else
 1581     {
 1582         basedir = (char *) SafeMalloc (strlen(user->pw_dir) +
 1583             strlen(CONF_CGIDIR) + 4, "script base directory");
 1584         sprintf(basedir, "%s/%s", user->pw_dir, CONF_CGIDIR);
 1585     }
 1586 
 1587     return basedir;
 1588 }
 1589 
 1590 
 1591 
 1592 /*
 1593  * Check that a file exists
 1594  */
 1595 int FileExists(char *path)
 1596 {
 1597     struct stat fileStat; /* For checking file status */
 1598 
 1599     if ( stat(path, &fileStat) )
 1600     {
 1601         return 0;
 1602     }
 1603 
 1604     if ( !S_ISREG(fileStat.st_mode) )
 1605     {
 1606         return 0;
 1607     }
 1608 
 1609     return 1;
 1610 }
 1611 
 1612 
 1613 
 1614 /*
 1615  * Check that a directory exists
 1616  */
 1617 int DirExists(char *path)
 1618 {
 1619     struct stat fileStat; /* For checking file status */
 1620 
 1621     if ( stat(path, &fileStat) )
 1622     {
 1623         return 0;
 1624     }
 1625 
 1626     if ( !S_ISDIR(fileStat.st_mode) )
 1627     {
 1628         return 0;
 1629     }
 1630 
 1631     return 1;
 1632 }