#!/usr/bin/perl -w ##=====================================================================## ## Copyright (C) 2001-2004 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,$gid,$dval) = ''; ## Want to add another configuration directive? Just add a new hash element. ## %etc_vars replaces @etc_vars, @ssh_vars, and %specdir use in earlier ## Sentry Firewall releases. ## Filename Directory my %etc_vars = ('httpd.conf', '/etc/apache', 'l2tpd.conf', '/etc/l2tp', 'sendmail.cf', '/etc/mail', 'portsentry.conf', '/etc/portsentry', 'pppoe.conf', '/etc/ppp', 'chap-secrets', '/etc/ppp', 'options', '/etc/ppp', 'options.l2tpd', '/etc/ppp', 'options.pptpd', '/etc/ppp', 'rc.6', '/etc/rc.d', 'rc.M', '/etc/rc.d', 'rc.dhcpd', '/etc/rc.d', 'rc.netdevice', '/etc/rc.d', 'rc.inet1', '/etc/rc.d', 'rc.inet1.conf', '/etc/rc.d', 'rc.inet2', '/etc/rc.d', 'rc.inet2.conf', '/etc/rc.d', 'rc.local', '/etc/rc.d', 'rc.modules', '/etc/rc.d', 'rc.firewall', '/etc/rc.d', 'rc.firewall.nat', '/etc/rc.d', 'rc.firewall.save', '/etc/rc.d', 'rc.keymap', '/etc/rc.d', 'rc.snort', '/etc/rc.d', 'rc.sendmail', '/etc/rc.d', 'rc.ntpd', '/etc/rc.d', 'smb.conf', '/etc/samba', 'shorewall.conf', '/etc/shorewall', 'squid.conf', '/etc/squid', 'ss5.conf', '/etc/ss5', 'ss5.passwd', '/etc/ss5', 'shosts.equiv', '/etc/ssh', 'ssh_config', '/etc/ssh', 'sshd_config', '/etc/ssh', 'ssh_host_dsa_key', '/etc/ssh', 'ssh_host_dsa_key.pub', '/etc/ssh', 'ssh_host_rsa_key', '/etc/ssh', 'ssh_host_rsa_key.pub', '/etc/ssh', 'ssh_host_key', '/etc/ssh', 'ssh_host_key.pub', '/etc/ssh', 'ssh_known_hosts', '/etc/ssh', 'ssh_known_hosts2', '/etc/ssh', 'openssl.cnf', '/etc/ssl', 'stunnel.conf', '/etc/stunnel', 'stunnel.pem', '/etc/stunnel', 'syslog-ng.conf', '/etc/syslog-ng', 'snmpd.conf', '/etc/ucd-snmp', 'miniserv.conf', '/etc/webmin', 'miniserv.pem', '/etc/webmin', 'miniserv.users', '/etc/webmin', 'webmin_config', '/etc/webmin', 'wlan.conf', '/etc/wlan', 'zebra.conf', '/etc/zebra', 'bgpd.conf', '/etc/zebra', 'ospfd.conf', '/etc/zebra', 'ripd.conf', '/etc/zebra', 'dhcpd.conf', '/etc', 'dnsmasq.conf', '/etc', 'ftpusers', '/etc', 'ftp-proxy.conf', '/etc', 'fstab', '/etc', 'gated.conf', '/etc', 'group', '/etc', 'hostname', '/etc', 'hosts', '/etc', 'hosts.equiv', '/etc', 'hosts.allow', '/etc', 'hosts.deny', '/etc', 'inetd.conf', '/etc', 'inittab', '/etc', 'ipsec.conf', '/etc', 'ipsec.secrets', '/etc', 'issue', '/etc', 'issue.net', '/etc', 'knockclient.conf', '/etc', 'knockdaemon.conf', '/etc', 'lpd.conf', '/etc', 'modules.conf', '/etc', 'motd', '/etc', 'named.conf', '/etc', 'newsyslog.conf', '/etc', 'ntp.conf', '/etc', 'passwd', '/etc', 'pptpd.conf', '/etc', 'profile', '/etc', 'proftpd.conf', '/etc', 'resolv.conf', '/etc', 'rinetd.conf', '/etc', 'rndc.conf', '/etc', 'shadow', '/etc', 'shells', '/etc', 'snort.conf', '/etc', 'syslog.conf', '/etc', 'ulogd.conf', '/etc', 'vsftpd.conf', '/etc'); ## "device" directive stuff. Setup networking. $net += &networking('NET_UP'); ## Take care of nameserver directive. &nameserver; ## Call include() to retrieve any include files. if ((exists($prefs{'include'})) && ($prefs{'include'} ne '')) { &do_include($net); } ## Call sub mount_cdrom() to try and mount the Sentry Firewall CD. print "Locating and mounting the Sentry Firewall CDROM...\n"; $status = &mount_cdrom; if ($status != 1) { &do_log("ERROR: CRITICAL - Unable to locate and mount a Sentry Firewall CDROM. Will try to proceed anyway."); print "ERROR: CRITICAL - Unable to locate and mount a Sentry Firewall CDROM. Will try to proceed anyway.\n"; } ## Call sub fix_modules() to populate /lib/modules. print "Configuring /lib/modules...\n"; &fix_modules; ## Initialize and add swap partition. &add_swap; ## Remount root to change size if needed. &root_size; ## Retrieve file if destination looks like a http(s)/(s)ftp/scp URL. ## Also checks to see if $prefs{"$var"} is a valid file. my $var = ''; foreach $var (keys %prefs) { $status = &vrfy_file($var); if ($status == 0) { &do_log("ERROR: Unable to locate \"$prefs{$var}\"."); delete($prefs{"$var"}) unless ($var eq 'hostname'); } } ## Complain loudly if user did not declare their own /etc/shadow file. &no_shadow; ## Do not start webmin if miniserv.users is not replaced, regardless of how ## the 'start_webmin' directive is set. &start_webmin; ## Clean up bare passwd/shadow/group files(wget needed these). foreach ('passwd', 'shadow', 'group') { unlink("/etc/$_"); } ## Remove /tmp/drivers, all devices should be set up by now. system("rm -rf /tmp/drivers 1>/dev/null 2>/dev/null"); ## Clean up statically-linked /bin/{ssh,sftp,scp,wget} files, only ## needed for network configuration support. foreach ('ssh', 'sftp', 'scp', 'wget') { unlink("/bin/$_"); } ## Copy important config files from $m_point to /etc/ ## At this time we're assuming $prefs{$dval} contains full path, including ## mount point. foreach $dval (keys %etc_vars) { if (!(-d "$etc_vars{$dval}")) { $etc_vars{$dval} = '/etc'; } $etc_vars{$dval} =~ s/^[\s\t]+//; $etc_vars{$dval} =~ s/[\s\t]+$//; if (exists($prefs{$dval})) { if ((("$dval" ne 'hostname') && !(-f "$prefs{$dval}")) || ($prefs{$dval} eq '')) { delete($prefs{$dval}); next; } &do_log("INFO: \'$dval\' 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 ("$dval" eq 'fstab') { &merge_fstab; } ## Merge user's shadow/passwd/group file with system default. elsif (("$dval" eq 'shadow') || ("$dval" eq 'passwd') || ("$dval" eq 'group')) { &merge_passwd($dval); } ## 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 ("$dval" eq 'hostname') { if (!(-f "$prefs{$dval}")) { if (open(FH,">/etc/HOSTNAME")) { flock(FH,2); print FH "$prefs{$dval}"; close(FH); } else { symlink('/etc/default/HOSTNAME', '/etc/HOSTNAME'); } } else { &pcopy("$prefs{$dval}", '/etc/HOSTNAME', PERM); } } ## Reread inittab if declared in config. elsif ("$dval" eq 'inittab') { &pcopy("$prefs{$dval}", '/etc/inittab', PERM); &do_log("INFO: \'inittab\' replaced, running \'telinit q\' to reread inittab."); system("/sbin/telinit q 1>/dev/null 2>/dev/null"); } ## Finally, just copy the files that don't need any special treatment. else { &pcopy("$prefs{$dval}", "$etc_vars{$dval}/${dval}", PERM); if (($dval eq 'named.conf') || ($dval eq 'rndc.conf')) { ## chrooted named. &pcopy("$prefs{$dval}", "/var/chroot/named/etc/${dval}", PERM); } elsif ($dval eq 'snort.conf') { ## chrooted snort. &pcopy("$prefs{$dval}", "/var/chroot/snort/etc/${dval}", PERM); } elsif (($dval eq 'ssh_host_rsa_key') || ($dval eq 'ssh_host_dsa_key') || ($dval eq 'ssh_host_key')) { chmod 0400, "/etc/ssh/${dval}"; } } ## Clean up tmp stuff(used when retrieving files via ftp/http(s)/sftp/scp). if (exists($prefs{$dval})) { if ($prefs{$dval} =~ /^\/tmp\//) { unlink("$prefs{$dval}"); } } delete($prefs{$dval}); ## Remove hash entry, done with it. } ## End if ## If file not declared in config, just pull it from /etc/default. ## More symlinks will be made later on for files not in %etc_vars. else { $etc_vars{$dval} =~ s/^\/etc//; if ((-f "/etc/default/$etc_vars{$dval}/${dval}") && (!(-f "/etc/$etc_vars{$dval}/${dval}"))) { symlink("/etc/default/$etc_vars{$dval}/${dval}", "/etc/$etc_vars{$dval}/${dval}"); } } } ## End foreach loop foreach $dval (keys %prefs) { next if (($prefs{$dval} eq '') || ($dval eq '')); next if ($dval eq 'debug'); next if ($dval =~ /^device\d$/); next if ($dval =~ /^(http|ftp)_proxy$/); next if ($dval =~ /^proxy\-(user|passwd)$/); next if ($dval =~ /^path\d{1,2}$/); ## Deal with cron:username directive. if ($dval =~ /^cron(tab)?\:/) { $uname = "$dval"; $uname =~ s/^cron(tab)?\://; $uid = (defined(getpwnam($uname))) ? getpwnam($uname) : "-1"; $gid = (defined(getgrnam($uname))) ? getgrnam($uname) : "0"; if ($uid >= 0) { &pcopy("$prefs{$dval}", "/var/spool/cron/crontabs/${uname}", PERM); chown(0, $gid, "/var/spool/cron/crontabs/${uname}"); chmod 0600, "/var/spool/cron/crontabs/${uname}"; } else { &do_log("ERROR: Syntax error in \"$dval\", user \"$uname\" does not exist."); } } else { &pcopy("$prefs{$dval}", "$dval", PERM); } delete($prefs{$dval}); } ## 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'); my $d = ''; foreach $d (@dirs) { next if ($d eq ''); next if !(-d "$d"); ## Note: $d should always be a valid directory. if (opendir(DIR, "$d")) { ## Get rid of '/etc/default/' in directory name. if ($d ne '/etc/default') { $d =~ s/^\/etc\/default\///; } ## Obviously, if the directory exists in /etc/default/$d but not ## in /etc/$d, then we shouldn't try to make symlinks from ## /etc/${d}/ to /etc/default/${d}/. next if (($d ne '/etc/default') && !(-d "/etc/${d}")); while (defined($filename = readdir(DIR))) { next if $filename =~ /^\.\.?$/; if ($d ne '/etc/default') { next if (-d "/etc/${d}/${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 ($d eq '/etc/default') { if (!(-e "/etc/${filename}") && !(-l "/etc/${filename}")) { symlink("/etc/default/${filename}", "/etc/${filename}"); } } elsif (!(-e "/etc/${d}/${filename}") && !(-l "/etc/${d}/${filename}")) { symlink("/etc/default/${d}/${filename}", "/etc/${d}/${filename}"); } } closedir(DIR); } else { &do_log("ERROR: Unable to open directory \"$d\"."); } } ## End foreach loop. return 1; } ## End sub do_config(). ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub nameserver(). ## Take care of nameserver directive. sub nameserver { return 0 if (!(exists($prefs{'nameserver'})) || ($prefs{'nameserver'} eq '')); &do_log("INFO: Processing \'nameserver\' directive..."); my @resolv_cnf = (); 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'}); return 1; } ## End sub nameserver(). ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub mount_cdrom() ## Attempts to mount the Sentry Firewall CD on /cdrom. Uses either what ## was defined with the "cdrom" directive in sentry.conf, or the information ## from `dmseg`. ide-scsi is not dealt with yet. Returns 1 on success. sub mount_cdrom { my $dev = ''; my $status = 0; my $mountpt = '/cdrom'; if (grep(/on\s+${mountpt}\s+/, `/bin/mount`)) { &do_log("ERROR: $mountpt appears to be mounted."); return 0; } if (exists($prefs{'cdrom'})) { $prefs{'cdrom'} =~ s/^\/+dev\/+//; if (-b "/dev/$prefs{cdrom}") { ## Mount /dev/$prefs{cdrom} on $mountpt. $status = &do_command("/bin/mount -r -t iso9660 /dev/$prefs{cdrom} $mountpt", '10'); if ($status == 1) { if (-d "${mountpt}/SENTRY") { &do_log("INFO: Sentry Firewall CD found on /dev/$prefs{cdrom}, mounted on ${mountpt}."); } else { &do_log("INFO: CD found on /dev/${_}, but does not appear to be a Sentry Firewall CD."); &do_command("/bin/umount $mountpt", '10'); $status = 0; } } else { &do_log("ERROR: An error occurred while trying to mount $prefs{cdrom} on ${mountpt}."); } } else { &do_log("ERROR: Syntax error in $prefs{cdrom}."); } delete($prefs{'cdrom'}); return 1 if ($status == 1); } ## Try to use the information from `dmesg` to mount the CD on $mountpt. if (!(grep(/on\s+${mountpt}\s+/, `/bin/mount`))) { ## Look for a detected IDE/ATAPI CD-ROM drive. If we find one, try to mount. ## We use temp var $dev 'cause $_ gets clobbered after call to do_command(). my @dmsg = `/bin/dmesg|grep ATAPI|grep CD`; foreach $dev (@dmsg) { chomp($dev); $dev =~ s/\:.*//; $dev =~ s/[\s\t]+//g; next if (!(-b "/dev/${dev}")); $status = &do_command("/bin/mount -r -t iso9660 /dev/${dev} $mountpt", '10'); if ($status == 1) { if (-d "${mountpt}/SENTRY") { &do_log("Sentry Firewall CD found on /dev/${dev}, mounted on ${mountpt}."); return 1; } else { &do_log("CD found on /dev/${dev}, but does not appear to be a Sentry Firewall CD."); &do_command("/bin/umount $mountpt", '10'); next; } } } ## End foreach loop(IDE/ATAPI). ## Look for and try to mount a SCSI CD-ROM drive. ## We use temp var $dev 'cause $_ gets clobbered after call to do_command(). @dmsg = `/bin/dmesg|grep "scsi CD-ROM sr"`; foreach $dev (@dmsg) { chomp($dev); $dev =~ s/Detected\s+scsi\s+CD\-ROM\s+//; $dev =~ s/\s.*//; $dev =~ s/[\s\t]+//g; next if (!(-b "/dev/${dev}")); $status = &do_command("/bin/mount -r -t iso9660 /dev/${dev} $mountpt", '10'); if ($status == 1) { if (-d "${mountpt}/SENTRY") { &do_log("Sentry Firewall CD found on /dev/${dev}, mounted on ${mountpt}."); return 1; } else { &do_log("CD found on /dev/${dev}, but does not appear to be a Sentry Firewall CD."); &do_command("/bin/umount $mountpt", '10'); next; } } } ## End foreach loop(SCSI). } return 0; } ## End sub mount_cdrom() ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub fix_modules() ## Copies or symlinks the contents of /cdrom/lib/modules/$kversion to ## /lib/modules/$kversion unless the filename is TRANS.TBL, created when ## the iso image was made. The presence of TRANS.TBL causes annoying errors ## with depmod. sub fix_modules { my $kversion = `uname -r`; chomp($kversion); $kversion =~ s/[\s\t]+//g; if (!(-d "/lib/modules/${kversion}")) { if (!(mkdir("/lib/modules/${kversion}", 0755))) { &do_log("ERROR: Unable to make directory /lib/modules/${kversion}, $!"); return 0; } } @dirs = (); &recurse_dirs('/cdrom/lib/modules', "$kversion"); push(@dirs, "/cdrom/lib/modules/${kversion}"); my $filename = ''; my $d = ''; foreach $d (@dirs) { next if ($d eq ''); next if !(-d "$d"); ## Note: $d should always be a valid directory. $d =~ s/^\/cdrom\///; if (!(-d "/${d}")) { mkdir("/${d}", 0755); } if (opendir(DIR, "/cdrom/${d}")) { while (defined($filename = readdir(DIR))) { next if $filename =~ /^\.\.?$/; next if $filename =~ /^TRANS\.TBL$/; if (-l "/cdrom/${d}/${filename}") { &pcopy("/cdrom/${d}/${filename}", "/${d}/${filename}", LINK); } elsif (-f "/cdrom/${d}/${filename}") { if ($filename =~ /^modules\.[A-Za-z0-9_-]+$/) { &pcopy("/cdrom/${d}/${filename}", "/${d}/${filename}"); } else { symlink("/cdrom/${d}/${filename}", "/${d}/${filename}"); } } } closedir(DIR); } else { &do_log("ERROR: fix_modules\(\): Unable to open directory \"/cdrom/${d}\"."); } } ## End foreach loop. ## Update timestamp of modules.dep. system('/bin/touch', "/lib/modules/${kversion}/modules.dep"); return 1; } ## End sub fix_modules(). ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub add_swap() ## Initialize and add swap partition. sub add_swap { my $format = '0'; if (exists($prefs{'add_swap'})) { $prefs{'add_swap'} =~ s/\/dev\/?//; if ($prefs{'add_swap'} =~ /\:format/) { $format = '1'; } $prefs{'add_swap'} =~ s/\:.*//; if (-e "/dev/$prefs{'add_swap'}") { if ($format eq '1') { print "Formatting swap partition on /dev/$prefs{add_swap}.\n"; system("/sbin/mkswap /dev/$prefs{add_swap} 1>/dev/null 2>/dev/null"); if ($? > 0) { print "ERROR: Error formatting swap partition. Swap partition will not be activated.\n"; &do_log("ERROR: Error formatting swap partition. Swap partition will not be activated."); delete($prefs{'add_swap'}); return 0; } } print "Activating swap partition on /dev/$prefs{add_swap}\n"; system("/sbin/swapon /dev/$prefs{add_swap} 1>/dev/null 2>/dev/null"); if ($? > 0) { print "ERROR: Error activating swap partition.\n"; &do_log("ERROR: Error activating swap partition."); delete($prefs{'add_swap'}); return 0; } } else { print "ERROR: /dev/$prefs{add_swap} does not exist.\n"; &do_log("ERROR: /dev/$prefs{add_swap} does not exist."); delete($prefs{'add_swap'}); return 0; } delete($prefs{'add_swap'}); } return 1; } ## End sub add_swap(). ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub root_size() ## Remount root to change size if needed. sub root_size { if (exists($prefs{'root_size'})) { if ($prefs{'root_size'} =~ /^\d+[GgMmKk]?$/) { if ($prefs{'root_size'} =~ /^\d+$/) { $prefs{'root_size'} .= 'M'; &do_log("INFO: No G,M,K suffix on variable root_size, presuming $prefs{root_size}."); } &do_log("INFO: changing size of root to $prefs{root_size}."); ## Add entry for root(/) in /etc/fstab. /etc/fstab does not yet exist ## but will be needed to remount root(/). if (open(FH, ">/etc/fstab")) { print FH "tmpfs / tmpfs defaults,size=18M 0 0\n"; close(FH); } system("mount -oremount,size=$prefs{root_size} / 1>/dev/null 2>/dev/null"); if ($? > 0) { &do_log("ERROR: Error changing size of root."); delete($prefs{'root_size'}); return 0; } unlink('/etc/fstab'); } delete($prefs{'root_size'}); } return 1; } ## End sub root_size(). ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub no_shadow(). ## Default password 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. sub no_shadow { if (!(exists($prefs{'shadow'}))) { print "WARNING: /etc/shadow not replaced, default passwords are inherently insecure!\n"; &do_log("WARNING: /etc/shadow not replaced. Reverting to more restrictive inetd.conf and sshd_config."); $prefs{'shadow'} = 'NULL'; } elsif (exists($prefs{'shadow'}) && !(-f "$prefs{shadow}")) { print "WARNING: /etc/shadow declared but not available.\n"; &do_log("WARNING: /etc/shadow not replaced. Reverting to more restrictive inetd.conf and sshd_config."); $prefs{'shadow'} = 'NULL'; } else { return 1; } if ($prefs{'shadow'} eq 'NULL') { ## 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'})) { &pcopy("$prefs{'inetd.conf'}", '/etc/inetd.conf.user', PERM); delete($prefs{'inetd.conf'}); } if (exists($prefs{'sshd_config'})) { &pcopy("$prefs{'sshd_config'}", '/etc/ssh/sshd_config.user', PERM); 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"); } delete($prefs{'shadow'}); } return 1; } ## End sub no_shadow(). ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub start_webmin(). ## Do not start webmin if miniserv.users is not replaced, regardless of how ## the 'start_webmin' directive is set. sub start_webmin { if (exists($prefs{'start_webmin'})) { $prefs{'start_webmin'} = lc($prefs{'start_webmin'}); if (($prefs{'start_webmin'} eq 'enable') || ($prefs{'start_webmin'} eq 'start') || ($prefs{'start_webmin'} eq 'on') || ($prefs{'start_webmin'} eq 'yes')) { if (!(exists($prefs{'miniserv.users'}))) { do_log('WARNING: miniserv.users not replaced. Unable to start Webmin.'); chmod 0444, '/etc/default/rc.d/rc.webmin'; } elsif (exists($prefs{'miniserv.users'}) && !(-f "$prefs{'miniserv.users'}")) { do_log('WARNING: miniserv.users declared but file was not found. Disabling Webmin.'); chmod 0444, '/etc/default/rc.d/rc.webmin'; delete($prefs{'miniserv.users'}); } else { chmod 0755, '/etc/default/rc.d/rc.webmin'; } } else { chmod 0444, '/etc/default/rc.d/rc.webmin'; } delete($prefs{'start_webmin'}); } else { chmod 0444, '/etc/default/rc.d/rc.webmin'; } return 1; } ## End Sub start_webmin(); ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub merge_fstab(). ## 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. sub merge_fstab { my (@sys_fstab, @usr_fstab) = (); my ($val, $val2) = ''; if (! -f "$prefs{'fstab'}") { &pcopy('/etc/default/fstab', '/etc/fstab', PERM); delete($prefs{'fstab'}); return 0; } if (open(FH,"<$prefs{'fstab'}")) { flock(FH,1); @usr_fstab = ; close(FH); } else { print "ERROR: merge_fstab(): Unable to read $prefs{'fstab'}.\n"; &do_log("ERROR: merge_fstab(): Unable to read $prefs{'fstab'}."); &pcopy('/etc/default/fstab', '/etc/fstab', PERM); delete($prefs{'fstab'}); return 0; } if (open(FH,"; close(FH); } else { &do_log("ERROR: merge_fstab(): Unable to read /etc/fstab."); &pcopy($prefs{'fstab'}, '/etc/fstab', PERM); delete($prefs{'fstab'}); return 0; } foreach $val (@sys_fstab) { $compare = $val; $compare =~ s/^[\s\t]+//; $compare =~ s/[\s\t]+.*//; foreach $val2 (@usr_fstab) { if ($val2 =~ /^[\s\t]*${compare}[\s\t]+/) { ## There's a dup, use the user's value instead. $val = ''; last; } } } if (open (FH,">/etc/fstab")) { flock(FH,2); foreach $val (@sys_fstab) { next if ($val eq ''); print FH "$val"; } foreach $val (@usr_fstab) { print FH "$val"; } } else { &do_log("ERROR: merge_fstab(): Unable to write to /etc/fstab."); &pcopy($prefs{'fstab'}, '/etc/fstab', PERM); delete($prefs{'fstab'}); return 0; } return 1; } ## End Sub merge_fstab(). ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub merge_passwd(). ## Merge user's shadow/passwd/group file with system default. sub merge_passwd { return 0 if (("$_[0]" ne 'shadow') && ("$_[0]" ne 'passwd') && ("$_[0]" ne 'group')); my $dval = "$_[0]"; my (@sysfile,@usr_sysfile) = (); my ($tmp,$tmp2,$compare) = ''; if (!(-f "$prefs{$dval}")) { &do_log("ERROR: $prefs{$dval} not found, /etc/${dval} not replaced."); print "WARNING: /etc/${dval} not found.\n"; symlink("/etc/default/${dval}", "/etc/${dval}"); delete($prefs{$dval}); return 0; } ## Put /etc/default/{passwd,shadow,group} into @sysfile, process @sysfile. 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/${dval}"); &pcopy("$prefs{$dval}", "/etc/${dval}", PERM); chmod(0600, "/etc/${dval}") if ($dval eq 'shadow'); delete($prefs{$dval}); return 0; } ## Put user's {passwd,shadow,group} into @usr_sysfile, process @usr_sysfile. if (open(FH,"<$prefs{$dval}")) { 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{$dval}"); symlink("/etc/default/${dval}", "/etc/${dval}"); delete($prefs{$dval}); return 0; } ## Compare passwd/shadow/group entries with user's. Only the ## first part, the user or group name, is matched. 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/${dval}")) { flock(FH,2); foreach $tmp (@usr_sysfile,@sysfile) { next if ($tmp eq ''); print FH "${tmp}\n"; } close(FH); chmod(0600, "/etc/${dval}") if ($dval eq 'shadow'); } else { &pcopy("$prefs{$dval}", "/etc/${dval}", PERM); chmod(0600, "/etc/${dval}") if ($dval eq 'shadow'); } return 1; } ## End sub merge_passwd(). ##-------------------------------------------------------------------------## ##-------------------------------------------------------------------------## ## Sub recurse_dirs() sub recurse_dirs { my $path = $_[0]; (return 0) if (!(defined($_[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() ##-------------------------------------------------------------------------## return 1; ## _EOF_ ##