#!/usr/bin/perl -w ##=====================================================================## ## Copyright (C) 2001-2002 Stephen Zarkos. All rights reserved. ## Obsid@Sentry.net ## ## Please see file: COPYRIGHT for further copyright information and ## disclaimer. Or online at http://www.SentryFirewall.com/files/COPYRIGHT ##=====================================================================## ## File: do_config.pl $ENV{PATH} = "/bin:/sbin"; umask 022; ##-------------------------------------------------------------------------## ## Sub do_config() ## Parses config in @conf and sets things up. sub do_config { my ($status,$filename,$uname,$uid) = ''; ## Want to add another configuration directive? Just add an array element. ## May also need to add an element to %specdir(). my (@etc_vars) = ('rc.M', 'rc.netdevice', 'rc.inet1', 'rc.inet2', 'rc.local', 'rc.modules', 'rc.firewall', 'rc.firewall.nat', 'passwd', 'shadow', 'group', 'fstab', 'hosts.equiv', 'profile', 'inetd.conf', 'snort.conf', 'proftpd.conf', 'shells', 'ftpusers', 'syslog.conf', 'named.conf', 'newsyslog.conf', 'resolv.conf', 'hosts', 'hostname', 'squid.conf', 'smb.conf', 'pptpd.conf', 'gated.conf', 'zebra.conf', 'syslog-ng.conf', 'pppoe.conf', 'smb.conf', 'httpd.conf', 'openssl.cnf', 'modules.conf', 'ntp.conf'); ## SSH host keys are created by rc.sshd if not supplied here, there are NO ## default ssh host keys on the rootdisk, for obvious reasons. my (@ssh_vars) = ('shosts.equiv', 'ssh_config', 'sshd_config', 'ssh_host_dsa_key', 'ssh_host_dsa_key.pub', 'ssh_host_rsa_key', 'ssh_host_rsa_key.pub', 'ssh_host_key', 'ssh_host_key.pub', 'ssh_known_hosts', 'ssh_known_hosts2'); ## Hash to tell me where certain config files should go, otherwise they'll just end ## up in /etc. ## Filename Directory my %specdir = ( 'squid.conf', '/etc/squid', 'smb.conf', '/etc/samba', 'zebra.conf', '/etc/zebra', 'httpd.conf', '/etc/apache', 'pppoe.conf', '/etc/ppp', 'syslog-ng.conf', '/etc/syslog-ng', 'openssl.cnf', '/etc/ssl'); ## "device" directive stuff. Setup networking. $net += &networking('NET_UP'); ## Nameserver directive if (exists($prefs{'nameserver'})) { &do_log("Processing \'nameserver\' directive..."); if ($prefs{'nameserver'} ne '') { my(@resolv_cnf) = (); $status = ''; if (-f "/etc/resolv.conf") { if (open(FH,"; close(FH); } } if (open(FH,">/etc/resolv.conf")) { flock(FH,2); print FH "nameserver $prefs{nameserver}\n"; foreach(@resolv_cnf) { print FH "$_"; } close(FH); } else { &do_log("ERROR: Unable to open /etc/resolv.conf"); } } delete($prefs{'nameserver'}); } ## Call include() to retrieve any include files. if (exists($prefs{'include'})) { if ($prefs{'include'} eq '') { delete($prefs{'include'}); } else { &do_include($net); } } ## Mount cdrom, saves a possible headache instead of relying on rc.cdrom. if (exists($prefs{'cdrom'})) { $prefs{'cdrom'} =~ s/^(\/.+\/)+//; if (($prefs{'cdrom'} =~ /^\w+\d*$/) && (-b "/dev/$prefs{cdrom}")) { if (open(FH, ">>/etc/default/fstab")) { flock(FH,2); ## Request Exclusive Lock print FH "\n/dev/$prefs{cdrom} /cdrom iso9660 defaults,ro 0 0\n"; close(FH); if (!(-l "/etc/rc.d/rc.cdrom")) { chmod 0444, "/etc/rc.d/rc.cdrom"; } else { chmod 0444, "/etc/default/rc.d/rc.cdrom"; } } else { &do_log("Syntax error in $prefs{cdrom}."); } } delete($prefs{'cdrom'}); } ## Check to see if $prefs{"$_"} is a valid file, and retrieve file ## if destination looks like a http(s)/(s)ftp/scp URL. foreach (keys %prefs) { next if (!($prefs{"$_"}) || ("$prefs{$_}" eq '')); next if ("$_" =~ /^device\d$/); next if ("$_" =~ /^(http|ftp)_proxy$/); next if ("$_" =~ /^proxy\-(user|passwd)$/); if (($prefs{"$_"} =~ /^[hH]{1}[tT]{2}[pP]{1}[sS]?:\/\//) || ($prefs{"$_"} =~ /^[sS]?[fF]{1}[tT]{1}[pP]{1}:\/\//) || ($prefs{"$_"} =~ /^[sS]{1}[cC]{1}[pP]{1}:\/\//)) { if ($net > "0") { $status = ""; $status = &retr_file($_,$prefs{"$_"}); if ($status !~ /^\d$/) { $prefs{$_} = "$status"; } if (($status eq "0") || !(-e "$prefs{$_}")) { print "ERROR: Unable to retrieve ${_}.\n"; &do_log("ERROR: Unable to retrieve ${_}."); delete($prefs{$_}); } } else { print "ERROR: Unable to retrieve ${_}, device not configured.\n"; &do_log("ERROR: Unable to retrieve ${_}, device not configured."); delete($prefs{$_}); } next; } ## Check to see if $prefs{"$_"} is a valid file. if (!(-f "$prefs{$_}")) { if (-f "${m_point}/$prefs{$_}") { $prefs{$_} =~ s/^\/+//; &do_log("WARNING: Using \"${m_point}/$prefs{$_}\" instead of \"$prefs{$_}\""); $prefs{"$_"} = "${m_point}/$prefs{$_}"; $prefs{"$_"} =~ s/\/{2,}/\//g; } else { &do_log("ERROR: \"$prefs{$_}\" does not exist."); delete($prefs{"$_"}); next; } } } ## Warnings ## If /etc/shadow is not replaced, display a warning about using default passwords. ## Also, do not utilize user's inetd.conf and sshd_config if declared. Use more ## restictive default ones instead to prevent sshd, telnetd, and ftpd from listening ## for external connections. if (!(exists($prefs{'shadow'}))) { print "WARNING: /etc/shadow not replaced, default passwords are inherently insecure!\n"; ## If user is using default /etc/shadow, don't allow inetd to run services. ## This may irritate some people... oh well, *tear* if (exists($prefs{'inetd.conf'})) { system("cp -p $prefs{'inetd.conf'} /etc/inetd.conf.user 1>/dev/null 2>/dev/null"); delete($prefs{'inetd.conf'}); } if (exists($prefs{'sshd_config'})) { system("cp -p $prefs{'sshd_config'} /etc/ssh/sshd_config.user 1>/dev/null 2>/dev/null"); delete($prefs{'sshd_config'}); } if (-f "/etc/default/inetd.conf.none") { symlink("/etc/default/inetd.conf.none", "/etc/inetd.conf"); } if (-f "/etc/default/ssh/sshd_config.local") { symlink("/etc/default/ssh/sshd_config.local", "/etc/ssh/sshd_config"); } } ## Clean up bare passwd/shadow/group files. foreach ('passwd', 'shadow', 'group') { if (-f "/etc/$_") { system('rm', '-f', "/etc/$_"); } } ## Copy important config files from $m_point to /etc/ ## At this time we're assuming $prefs{$_} contains full path, including ## mount point. foreach (@etc_vars) { if (exists($prefs{$_})) { if ((("$_" ne 'hostname') && !(-f "$prefs{$_}")) || ($prefs{$_} eq '')) { delete($prefs{$_}); next; } &do_log("\'$_\' directive found."); ## Merge user's fstab with system default. ## This isn't perfect, but we do this because there are certain ## fstab entries that should exist by default. if ("$_" eq 'fstab') { my @usr_fstab = (); my @def_fstab = (); my ($tmpdev,$tmpmnt) = ''; my $entry = ''; if (-f "$prefs{$_}") { if (open(FH,"<$prefs{$_}")) { flock(FH,1); @usr_fstab = ; close(FH); } else { $status = "0"; } } else { print "Error: $prefs{$_}, file does not exist.\n"; $status = "0"; } ## No need to go through all this if we cannot get user's fstab. if (!(-f "$prefs{$_}") || ($status eq "0")) { delete($prefs{'fstab'}); next; } ## Copy default fstab to /etc, read contents to @def_fstab if (-f "/etc/default/fstab") { system("cp -p /etc/default/fstab /etc/fstab 1>/dev/null 2>/dev/null"); } if (-f "/etc/fstab") { if (open(FH,"; close(FH); } } foreach (@def_fstab) { chomp($_); $_ =~ s/#.*//; $_ =~ s/^[\s\t]+//; next if ($_ eq ''); $_ =~ s/[\s\t]+/ /g; $_ =~ s/^[\w\d\/\-\.]+\s[\w\d\/\-\.]+//; $_ = "$&"; } if (open(FH,">>/etc/fstab")) { flock(FH,2); ## Request Exclusive Lock print FH "\n"; foreach $entry (@usr_fstab) { chomp($entry); $entry =~ s/#.*//; $entry =~ s/^[\s\t]+//; $entry =~ s/[\s\t]+$//; next if ($entry eq ''); foreach (@def_fstab) { next if ($_ eq ''); ($tmpdev,$tmpmnt) = split(/\s/,$_,2); if (($entry =~ /^${tmpdev}[\s\t]/) || ($entry =~ /[\s\t]${tmpmnt}[\s\t]/) || ($entry =~ /[\s\t]\/usr[\s\t]/)) { $entry = ''; last; } } if ($entry ne '') { print FH "$entry\n"; } } ## End foreach close(FH); } else { &do_log("ERROR: Unable to open /etc/fstab while processing 'fstab' directive."); } } ## End If (fstab) ## Merge user's shadow/passwd/group file with system default. elsif (("$_" eq 'shadow') || ("$_" eq 'passwd') || ("$_" eq 'group')) { if (!(-f "$prefs{$_}")) { &do_log("ERROR: $prefs{$_} not found, /etc/$_ not replaced."); print "WARNING: /etc/$_ not replaced.\n"; symlink("/etc/default/$_", "/etc/$_"); delete($prefs{$_}); next; } ## Put /etc/default/{passwd,shadow,group} into @sysfile, process @sysfile. my(@sysfile,@usr_sysfile) = (); my($tmp,$tmp2,$compare) = ''; if (open(FH,"; close(FH); foreach $tmp (@sysfile) { chomp($tmp); $tmp =~ s/^[\s\t]+//; $tmp =~ s/[\s\t]+$//; } } else { &do_log("ERROR: Unable to open /etc/default/$_"); system("cp -p $prefs{$_} /etc/$_ 1>/dev/null 2>/dev/null"); (chmod 0600, "/etc/$_") if ($_ eq 'shadow'); delete($prefs{$_}); next; } ## Put user's {passwd,shadow,group} into @usr_sysfile, process @usr_sysfile. if (open(FH,"<$prefs{$_}")) { flock(FH,1); @usr_sysfile = ; close(FH); foreach $tmp (@usr_sysfile) { chomp($tmp); $tmp =~ s/^[\s\t]+//; $tmp =~ s/[\s\t]+$//; } } else { &do_log("ERROR: Unable to open $prefs{$_}"); symlink("/etc/default/$_", "/etc/$_"); @sysfile = (); delete($prefs{$_}); next; } ## Compare passwd/shadow/group entries with user's. Only the ## first part, the user or group name, is matched. In this case, ## unlike above with /etc/fstab, if there is a match the user's ## entry replaces the system default. foreach $tmp (@usr_sysfile) { $compare = "${tmp}"; $compare =~ s/\:.*//; next if ($compare eq ''); foreach $tmp2 (@sysfile) { if (${tmp2} =~ /^${compare}\:/) { ${tmp2} = ''; last; } } } if (open(FH,">/etc/${_}")) { flock(FH,2); foreach $tmp (@sysfile,@usr_sysfile) { next if ($tmp eq ''); print FH "${tmp}\n"; } close(FH); (chmod 0600, "/etc/$_") if ($_ eq 'shadow'); } else { system("cp -p $prefs{$_} /etc/$_ 1>/dev/null 2>/dev/null"); (chmod 0600, "/etc/$_") if ($_ eq 'shadow'); } (@sysfile,@usr_sysfile) = (); } ## End elsif (passwd,shadow,group). ## Deal with the 'hostname' directive. ## Pretty trivial right now, if $prefs{'hostname'} is not a path to an ## existing file, then we assume it's an actual hostname and put it in ## /etc/HOSTNAME. elsif ("$_" eq 'hostname') { if (!(-f "$prefs{$_}")) { if (open(FH,">/etc/HOSTNAME")) { flock(FH,2); print FH "$prefs{$_}"; close(FH); } else { symlink("/etc/default/HOSTNAME", "/etc/HOSTNAME"); } } else { system("cp -p $prefs{$_} /etc/HOSTNAME 1>/dev/null 2>/dev/null"); } } ## Finally, just copy the files that don't need any special treatment. else { if (exists($specdir{$_}) && (-d "$specdir{$_}")) { ## Copy file to proper directory as specified in $specdir{$_} variable system("cp -p $prefs{$_} $specdir{$_}/${_} 1>/dev/null 2>/dev/null"); } else { if ($_ =~ /^rc\./) { system("cp -p $prefs{$_} /etc/rc.d/$_ 1>/dev/null 2>/dev/null"); } else { system("cp -p $prefs{$_} /etc/$_ 1>/dev/null 2>/dev/null"); if ($prefs{$_} eq 'named.conf') { ## For chrooted named. system("cp -p $prefs{$_} /var/chroot/etc/$_ 1>/dev/null 2>/dev/null"); } } } } ## Clean up tmp stuff(used when retrieving files via ftp/http(s)/sftp/scp). if ($prefs{$_} =~ /^\/tmp\//) { system('rm', '-f', "$prefs{$_}"); } delete($prefs{$_}); ## Remove hash entry, done with it. } ## End if ## If file not declared in config, just pull it from /etc/default. else { if ($_ =~ /^rc\./) { if ((-f "/etc/default/rc.d/$_") && (!(-f "/etc/rc.d/$_"))) { symlink("/etc/default/rc.d/$_", "/etc/rc.d/$_"); } } elsif ((-f "/etc/default/$_") && (!(-f "/etc/$_"))) { symlink("/etc/default/$_", "/etc/$_"); } } } ## End foreach loop foreach (@ssh_vars) { if (exists($prefs{$_})) { if (($prefs{$_} eq '') || !(-f "$prefs{$_}")) { delete($prefs{$_}); next; } &do_log("\'$_\' directive found."); system("cp -p $prefs{$_} /etc/ssh/$_ 1>/dev/null 2>/dev/null"); if (($prefs{$_} =~ /^ssh_host_rsa_key$/) || ($prefs{$_} =~ /^ssh_host_dsa_key$/) || ($prefs{$_} =~ /^ssh_host_key$/)) { chmod 0400, "/etc/ssh/$_"; } ## Clean up tmp stuff. if (($prefs{$_} =~ /^\/tmp\//) && (-f "$prefs{$_}")) { system('rm', '-f', "$prefs{$_}"); } delete($prefs{$_}); ## Remove hash entry. } } foreach (keys %prefs) { next if (($prefs{$_} eq '') || ($_ eq '')); next if ("$_" =~ /^device\d$/); next if ("$_" =~ /^(http|ftp)_proxy$/); next if ("$_" =~ /^proxy\-(user|passwd)$/); # ## Check to see if $prefs{"$_"} is a valid file. # if (!(-f "$prefs{$_}")) { # if (-f "${m_point}/$prefs{$_}") { # $prefs{$_} =~ s/^\/+//; # &do_log("WARNING: Using \"${m_point}/$prefs{$_}\" instead of \"$prefs{$_}\""); # $prefs{"$_"} = "${m_point}/$prefs{$_}"; # $prefs{"$_"} =~ s/\/{2,}/\//g; # } # else { # &do_log("ERROR: $prefs{$_} does not exist."); # delete($prefs{"$_"}); # next; # } # } ## Deal with cron:username directive. if ($_ =~ /^cron(tab)?\:/) { $uname = "$_"; $uname =~ s/^cron(tab)?\://; $uid = (getpwnam("$uname") or ($uid = -1)); if ($uid >= 0) { system("cp -p $prefs{$_} /var/spool/cron/crontabs/${uname} 1>/dev/null 2>/dev/null"); chmod 0600, "/var/spool/cron/crontabs/${uname}"; } else { &do_log("ERROR: Syntax error in \"$_\", user \"$uname\" does not exist."); } } else { if ("$prefs{$_}" ne "$_") { system('cp', '-p', "$prefs{$_}", "$_"); } } delete($prefs{$_}); } ## Take down networking stuff if ($net ne "0") { &networking('NET_DOWN'); } ## That's it for the config. ## Make rest of the symlinks from /etc to /etc/default print "Completing configuration, using: /etc/default\n"; @dirs = ('/etc/default'); ## Call recurse_dirs(), recurses through /etc/default and fills @dirs with directory ## names. Kind of an expensive operation, but useful when we start making symlinks ## from /etc/{dir} to /etc/default/{dir}. &recurse_dirs('/etc', 'default'); foreach (@dirs) { next if ($_ eq ''); next if !(-d "$_"); ## Note: $_ should always be a valid directory. if (opendir(DIR, "$_")) { ## Get rid of '/etc/default/' in directory name. if ($_ ne '/etc/default') { $_ =~ s/^\/etc\/default\///; } ## Obviously, if the directory exists in /etc/default/$_ but not ## in /etc/$_, then we shouldn't try to make symlinks from ## /etc/$_/ to /etc/default/$_/. next if (($_ ne '/etc/default') && !(-d "/etc/${_}")); while (defined($filename = readdir(DIR))) { next if $filename =~ /^\.\.?$/; if ($_ ne '/etc/default') { next if (-d "/etc/${_}/${filename}"); } else { next if (-d "/etc/${filename}"); } ## Files we don't want symlinks to. next if ($filename eq 'sentry.conf'); next if ($filename eq 'sshd_config.local'); ## Finally, make the symlinks... if ($_ eq '/etc/default') { if (!(-e "/etc/${filename}") && !(-l "/etc/${filename}")) { symlink("/etc/default/${filename}", "/etc/${filename}"); } } elsif (!(-e "/etc/${_}/${filename}") && !(-l "/etc/${_}/${filename}")) { symlink("/etc/default/${_}/${filename}", "/etc/${_}/${filename}"); } } closedir(DIR); } else { &do_log("ERROR: Unable to open directory \"$_\"."); } } ## End foreach loop. } ## End sub do_config() ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub recurse_dirs() sub recurse_dirs { my($path) = $_[0]; my($dir) = $_[1]; my($filename) = ''; my($filehandle) = rand(500); if (opendir($filehandle, "${path}/${dir}")) { while (defined($filename = readdir($filehandle))) { next if $filename =~ /^\.\.?$/; next if ((-l "${path}/${dir}/$filename") || !(-d "${path}/${dir}/$filename")); push(@dirs, "${path}/${dir}/${filename}"); &recurse_dirs("${path}/${dir}", "${filename}"); } closedir($filehandle); } } ## End sub recurse_dirs() ##-------------------------------------------------------------------------## ## _EOF_ ##