#!/usr/bin/perl -w # Script to lock/unlock system files by making them immutable. # Unlocking must be done as root from single user mode. # This is derived from code by George Shaffer: # --- # Copyright 2000, 2001 GeodSoft, LLC - geodsoft.com / # George Shaffer (gshaffer@erols.com) # Anyone may use or modify this code for any purpose PROVIDED # that as long as it is recognizably derived from this code, # that this copyright notice, remains intact and unchanged. # No warrantees of any kind are expressed or implied. # --- # Written 11 June 2004 by Jim Lippard (version 1.0). # Modified 9 November 2006 by Jim Lippard to add do-not-recurse option (version 1.1). # File paths beginning with a + will not have contents of subdirectories locked or # unlocked. ### Required packages. use strict; ### Global constants. my $CONFIG_FILE = '/etc/syslock.conf'; my $VERSION = '1.1 of 9 November 2006'; my $LOCK = 0; my $UNLOCK = 1; my $SCHG_OR_UCHG = 'schg'; my $MOUNT_COMMAND = 'mount -uw /'; my $LOCK_COMMAND = "/usr/bin/chflags $SCHG_OR_UCHG"; my $RECURSIVE_LOCK_COMMAND = "/usr/bin/chflags -R $SCHG_OR_UCHG"; my $UNLOCK_COMMAND = "/usr/bin/chflags no$SCHG_OR_UCHG"; my $RECURSIVE_UNLOCK_COMMAND = "/usr/bin/chflags -R no$SCHG_OR_UCHG"; my $SECURELEVEL_COMMAND = '/sbin/sysctl kern.securelevel'; ### Global variables. my ($mode, $level, @files, $file, %dont_recurse); ### Main program. if ($0 =~ /syslock$/) { $mode = $LOCK; } elsif ($0 =~ /sysunlock$/) { $mode = $UNLOCK; } else { die "syslock/sysunlock: I've been invoked under someone else's name: $0\n"; } # If lock, no securelevel requirement. # If unlock, securelevel must be < 2. $level = `$SECURELEVEL_COMMAND`; $level =~ s/kern\.securelevel\s*=\s*(\d+)/$1/; if ($mode == $UNLOCK && $level > 1) { die "System securelevel is $level; sysunlock requires securelevel < 2.\n"; } open (CONFIG, $CONFIG_FILE) || die "Cannot open config file. $CONFIG_FILE\n"; while () { chop; if (/^\s*$|^\s*#/) { # Comment or blank space. } elsif (/^\+(.*)/) { $dont_recurse{$1} = 1; push (@files, $1); } else { push (@files, $_); } } close (CONFIG); # If / happens to be mounted as readonly, make it writeable. system "$MOUNT_COMMAND"; foreach $file (@files) { if ($mode == $LOCK) { if (-d $file) { if ($dont_recurse{$file}) { system "$LOCK_COMMAND $file/*"; system "$LOCK_COMMAND $file"; } else { system "$RECURSIVE_LOCK_COMMAND $file"; } } else { system "$LOCK_COMMAND $file"; } } else { if (-d $file) { if ($dont_recurse{$file}) { system "$UNLOCK_COMMAND $file"; system "$UNLOCK_COMMAND $file/*"; } else { system "$RECURSIVE_UNLOCK_COMMAND $file"; } } else { system "$UNLOCK_COMMAND $file"; } } }