CGI and Perl

File Permissions Setup and Monitoring Changes in the System

Another aspect of server configuration to consider is the permissions on the programs, directories, logs, and configuration files themselves, which comprise the installed httpd server. In general, under UNIX, the installation of an http server will create the following directories with their intent:

cgi-bin CGI programs to be executed by the server
conf Configuration files for the server
htdocs The top-level directory for the archive
icons/images Common image files and icon bitmaps
logs Logfiles are created here by httpd
support Programs used for maintenance of the server

The important thing here is to be sure that the appropriate access is afforded to the appropriate components of this structure, while maintaining privacy and some level of security through obscurity against uninvited snoopers. If you're managing your archive as a team, you will probably create a group-ID for the members of the team who will be modifying the contents. These people may also need to access the files within the directories listed in the preceding list. Thus, it's recommended to make all of the files and directories within the list owned by root and accessible by the group you've created for the Web team--something like this:

drwx--x--x  2 root www         512 May 10 21:36 cgi-bin/
 drwx------  2 root www         512 Jul 20 16:11 conf/
 drwxr-xr-x  3 root www         512 May 14 16:02 htdocs/
 -rwx------  1 root www      155648 May  5 15:33 httpd*
 drwxr-xr-x  2 root www        1024 Feb 17 00:32 icons/
 drwx------  2 root www         512 Jun 23 11:28 logs/
 drwxr-xr-x  2 root www         512 Feb 17 00:32 support/

In this case, the restrictions on the logs directory or the conf directory may be excessive, again depending on the level of access you wish to provide. If the person who has the root password can't be bothered to create new directories under the htdocs directory, to truncate/archive the logfiles periodically, or to modify the configuration options within the config files, then these files or directories may need to have write-perms for the group www, or possibly ownership by the userid, www. The most important thing is that root owns the server binary itself, httpd, and that the userid the server runs under (nobody) has no write permissions to anything within this hierarchy.

It's a good idea to use some sort of security package, like TripWire or COPS, to occasionally verify that these permissions haven't been changed. Such a practice is also useful for the detection of unwanted files or changed files within your archive. This will be discussed further in the next section. We'll take a closer look at these tools at the end of the chapter. For now, we can add a few lines to the previous script to check some of the most important of these permissions for us:

use HTTPD::Config;
 require "stat.pl";
 $conf =  `/usr/local/etc/httpd/conf';
 @files = qw(httpd.conf srm.conf access.conf);
 $V= new HTTPD::Config (SERVER => Apache,
                              SERVER_ROOT => $conf,
                              FILES => [@files]);
 print "Userid: ", $V->user,"\n";
 print "Group: ", $V->group,"\n";
 print "Administrator is: ", $V->server_admin,"\n";
 print "Running at port: ", $V->port,"\n";
 print "Access filename: ",$V->access_file_name,"\n";
 print "User Directory: ", $V->user_dir,"\n";
 print "Global Types:\t", join("\n\t\t",$V->add_type),"\n";
 print "\n\n";
 foreach $dir (keys %{$V->{`Directory'}}){
     print "Options for Directory: $dir\n";
     while(($opt,$val) = each %{$V->{`Directory'}{$dir}{`OPTIONS'}}){
         print "\t",$opt, " : ", @{$val},"\n";
     }
 }
 # rudimentary permissions checking
 $webuser = (getpwnam($V->user))[2];
 opendir(ROOT,$V->server_root);
 @files = grep(!/\.\.?/,readdir(ROOT));
 closedir(ROOT);
 foreach $f (@files){
     @s = Stat($V->server_root."/$f");
     if($s[$ST_UID] == $webuser){
         print "Warning: ",$V->server_root,"/$f is owned by ",
                 $V->user,"\n\n";
     }
     if($f eq "httpd"){
         if(($s[$ST_MODE] != 0100700) or ($s[$ST_UID] != 0)){
             print "\tWarning: ",$V->server_root,"/httpd may have\n";
             print "\tpermission problems.  Recommend root ownership\n";
             print "\tand readable, writable and executable only by\n";
             print "\troot user\n";
         }
     }
 }

Now, when we run our simple security script, we'll get a warning if anything in the RootDir is owned by the userid that runs the server, or if the httpd itself isn't owned by root with the permissions specified in the preceding code. Note that we used the old stat.pl library in this example, as well. It provides a simplified interface to the stat(2) function.