--- /dev/null
+# This is -*- perl -*-
+
+package OpenAFS::Auth;
+use strict;
+use warnings;
+use OpenAFS::Dirpath;
+use OpenAFS::ConfigUtils;
+
+my $path = $OpenAFS::Dirpath::openafsdirpath;
+
+#
+# Create an auth type for the specified Kerberos implementation.
+#
+# parameters:
+# type -- Kerberos implementation: mit, heimdal, kaserver
+# keytab -- path and name of the keytab file for mit and heimdal
+# cell -- cell name. if not specified, attempts to find the
+# cell name in the ThisCell configuration file.
+# realm -- realm name. if not specified, assume the realm name
+# is the same as the cell name, in uppercase.
+#
+# example:
+# my $auth = OpenAFS::Auth::create(
+# 'type'=>'mit',
+# 'keytab'=>'/path/to/file/krb5.keytab');
+#
+# $auth->authorize('admin');
+#
+sub create {
+ my $self = {
+ # default values
+ 'type' => 'MIT',
+ 'keytab' => "$path->{'afsconfdir'}/krb5.keytab",
+ 'cell' => '',
+ 'realm' => '',
+ 'debug' => '0',
+ # user specified values
+ @_,
+ };
+
+ # check for supported kerberos type.
+ my $type = $self->{'type'};
+ $self->{'type'} = _check_kerberos_type($type) or
+ die "Unsupported kerberos type: $type\n";
+
+ # create the sub-class for the kerberos type.
+ my $class = "OpenAFS::Auth::$self->{'type'}";
+ $self = bless($self, $class);
+
+ # attempt get default values.
+ unless ($self->{'cell'}) {
+ eval {
+ $self->{'cell'} = $self->_lookup_cell_name();
+ }
+ }
+ unless ($self->{'realm'}) {
+ if ($self->{'cell'}) {
+ my $cell = $self->{'cell'};
+ ($self->{'realm'} = $cell) =~ tr[a-z][A-Z];
+ }
+ }
+ unless ($self->{'keytab'}) {
+ $self->{'keytab'} = "$path->{'afsconfdir'}/krb5.keytab";
+ }
+
+ # kerberos type specific sanity checks.
+ $self->_sanity_check();
+
+ if ($self->debug) {
+ print "debug: Auth::create()\n";
+ foreach my $k (sort keys(%$self)) {
+ print "debug: $k => $self->{$k}\n";
+ }
+ }
+ return $self;
+}
+
+#
+# Check for supported kerberos type, and allow for case insensitivity.
+#
+sub _check_kerberos_type {
+ my $type = shift;
+ foreach my $supported ('MIT', 'Heimdal', 'Kaserver') {
+ if ($type =~ /^$supported$/i) {
+ return $supported;
+ }
+ }
+ return undef;
+}
+
+#
+# Returns the cell name from the ThisCell configuration file.
+#
+sub _lookup_cell_name {
+ my $self = shift;
+ my $cell;
+ open(CELL, "$path->{'afsconfdir'}/ThisCell")
+ or die "error: Cannot open $path->{'afsconfdir'}/ThisCell: $!\n";
+ $cell = <CELL>;
+ chomp $cell;
+ close CELL;
+ return $cell;
+}
+
+#
+# Placeholder for make_keyfile. Sub-classes should override.
+#
+sub make_keyfile {
+ my $self = shift;
+ return;
+}
+
+#
+# Make the krb.conf file if the realm name is different
+# than the cell name. The syntax is something like,
+#
+# UMICH.EDU
+# UMICH.EDU fear.ifs.umich.edu admin server
+# UMICH.EDU surprise.ifs.umich.edu
+# UMICH.EDU ruthless.ifs.umich.edu
+#
+sub make_krb_config {
+ my $self = shift;
+ my $cell = $self->{'cell'};
+ my $realm = $self->{'realm'};
+
+ if ($realm && $realm ne $cell) {
+ unless ( -d $path->{'afsconfdir'} ) {
+ die "error: OpenAFS configuration directory '$path->{'afsconfdir'}' is missing.\n";
+ }
+ unless ( -w $path->{'afsconfdir'} ) {
+ die "error: Write access to the configuration directory '$path->{'afsconfdir'}' is required.\n";
+ }
+ print "debug: Making $path->{'afsconfdir'}/krb.conf file for realm $realm\n" if $self->{'debug'};
+ open(KRB, "> $path->{'afsconfdir'}/krb.conf") or die "error: Failed to open $path->{'afsconfdir'}/krb.conf, $!\n";
+ print KRB "$realm\n";
+ close KRB;
+ }
+}
+
+#
+# Enable/disable debug messages.
+#
+sub debug {
+ my $self = shift;
+ if (@_) {
+ $self->{'debug'} = shift;
+ }
+ return $self->{'debug'};
+}
+
+
+#------------------------------------------------------------------------------------
+# MIT Kerberos authorization commands.
+#
+package OpenAFS::Auth::MIT;
+use strict;
+use OpenAFS::Dirpath;
+use OpenAFS::ConfigUtils;
+our @ISA = ("OpenAFS::Auth");
+
+#
+# Sanity checks before we get started.
+#
+sub _sanity_check {
+ my $self = shift;
+ unless (defined $path->{'afssrvbindir'}) {
+ die "error: \$path->{'afssrvbindir'} is not defined.\n";
+ }
+ unless (-f "$path->{'afssrvbindir'}/aklog") {
+ die "error: $path->{'afssrvbindir'}/aklog not found.\n";
+ }
+ unless (-x "$path->{'afssrvbindir'}/aklog") {
+ die "error: $path->{'afssrvbindir'}/aklog not executable.\n";
+ }
+ unless ($self->{'realm'}) {
+ die "error: Missing realm parameter Auth::create().\n";
+ }
+ unless ($self->{'keytab'}) {
+ die "error: Missing keytab parameter Auth::create().\n";
+ }
+ unless ( -f $self->{'keytab'} ) {
+ die "error: Kerberos keytab file not found: $self->{'keytab'}\n";
+ }
+ unless ( -f $self->{'keytab'} ) {
+ die "error: Keytab file not found: $self->{'keytab'}\n";
+ }
+}
+
+#
+# Create the KeyFile from the Kerberos keytab file. The keytab file
+# should be created using the Kerberos kadmin command (or with the kadmin.local command
+# as root on the KDC). See the OpenAFS asetkey man page for details.
+#
+sub make_keyfile {
+ my $self = shift;
+
+ # asetkey annoyance. The current asetkey implementation requires the ThisCell and CellServDB files
+ # to be present but they really are not needed to create the KeyFile. This check is done here
+ # rather than in the _sanity_checks() because the ThisCell/CellServerDB are created later in
+ # the process of creating the new cell.
+ unless ( -f "$path->{'afsconfdir'}/ThisCell" ) {
+ die "error: OpenAFS configuration file is required, $path->{'afsconfdir'}/ThisCell\n";
+ }
+ unless ( -f "$path->{'afsconfdir'}/CellServDB" ) {
+ die "error: OpenAFS configuration file is required, $path->{'afsconfdir'}/CellServDB\n";
+ }
+
+ unless ( -f "$path->{'afssrvbindir'}/asetkey" ) {
+ die "error: $path->{'afssrvbindir'}/asetkey is missing.\nWas OpenAFS built with Kerberos support?\n";
+ }
+ unless ( -x "$path->{'afssrvbindir'}/asetkey" ) {
+ die "error: Do not have execute permissions on $path->{'afssrvbindir'}/asetkey\n";
+ }
+ unless ( -d $path->{'afsconfdir'} ) {
+ die "error: OpenAFS configuration directory '$path->{'afsconfdir'}' is missing.\n";
+ }
+ unless ( -w $path->{'afsconfdir'} ) {
+ die "error: Write access to the OpenAFS configuration directory '$path->{'afsconfdir'}' is required.\n";
+ }
+
+
+ # Run klist to get the kvno of the afs key. Search for afs/cellname@REALM
+ # then afs@REALM. klist must be in the path.
+ my %keys = ();
+ my $kvno;
+ my $principal;
+ my $afs_kvno;
+ my $afs_principal;
+ if ($self->debug) {
+ print "debug: reading $self->{'keytab'} to find afs kvno\n";
+ }
+ open(KLIST, "klist -k $self->{'keytab'} |") or die "make_keyfile: Failed to run klist.";
+ while (<KLIST>) {
+ chomp;
+ next if /^Keytab/; # skip headers
+ next if /^KVNO/;
+ next if /^----/;
+ ($kvno, $principal) = split;
+ if ($self->debug) {
+ print "debug: kvno=$kvno principal=$principal\n";
+ }
+ $keys{$principal} = $kvno;
+ }
+ close KLIST;
+ my $cell = $self->{'cell'};
+ my $realm = $self->{'realm'};
+ foreach my $principal ("afs/$cell\@$realm", "afs\@$realm") {
+ if ($self->debug) {
+ print "debug: searching for $principal\n";
+ }
+ if (defined $keys{$principal}) {
+ $afs_principal = $principal;
+ $afs_kvno = $keys{$afs_principal};
+ if ($self->debug) {
+ print "debug: found principal=$afs_principal kvno=$afs_kvno\n";
+ }
+ last;
+ }
+ }
+ unless ($afs_kvno) {
+ die "error: Could not find an afs key matching 'afs/$cell\@$realm' or ".
+ "'afs/$cell' in keytab $self->{'keytab'}\n";
+ }
+
+ # Run asetkey on the keytab to create the KeyFile. asetkey must be in the PATH.
+ run("$path->{'afssrvbindir'}/asetkey add $afs_kvno $self->{'keytab'} $afs_principal");
+}
+
+#
+# Get kerberos ticket and AFS token for the user.
+#
+sub authorize {
+ my $self = shift;
+ my $principal = shift || 'admin';
+ my $opt_aklog = "";
+ $opt_aklog .= " -d" if $self->debug;
+
+ run("kinit -k -t $self->{'keytab'} $principal");
+ run("$path->{'afssrvbindir'}/aklog $opt_aklog");
+ run("$path->{'afssrvbindir'}/tokens");
+}
+
+
+#------------------------------------------------------------------------------------
+package OpenAFS::Auth::Heimdal;
+use strict;
+use OpenAFS::Dirpath;
+use OpenAFS::ConfigUtils;
+our @ISA = ("OpenAFS::Auth");
+
+#
+# Various checks during initialization.
+#
+sub _sanity_check {
+ my $self = shift;
+ unless ($self->{'realm'}) {
+ die "Missing realm parameter Auth::create().\n";
+ }
+ unless ($self->{'keytab'}) {
+ die "Missing keytab parameter Auth::create().\n";
+ }
+ unless ( -f $self->{'keytab'} ) {
+ die "keytab file not found: $self->{'keytab'}\n";
+ }
+}
+
+#
+# Get kerberos ticket and AFS token for the user.
+#
+sub authorize {
+ my $self = shift;
+ my $principal = shift || 'admin';
+ run("kinit -k -t $self->{'keytab'} $principal\@$self->{'realm'} && afslog");
+}
+
+#------------------------------------------------------------------------------------
+package OpenAFS::Auth::Kaserver;
+use strict;
+use OpenAFS::Dirpath;
+use OpenAFS::ConfigUtils;
+our @ISA = ("OpenAFS::Auth");
+
+#
+# Various checks during initialization.
+#
+sub _sanity_check {
+ my $self = shift;
+ unless ($self->{'realm'}) {
+ die "Missing realm parameter Auth::create().\n";
+ }
+}
+
+#
+# Get kerberos ticket and AFS token for the user.
+#
+sub authorize {
+ my $self = shift;
+ my $principal = shift || 'admin';
+ run("echo \"Proceeding w/o authentication\"|klog -pipe ${principal}\@$self->{'realm'}");
+}
+
+1;
--- /dev/null
+# This is -*- perl -*-
+
+package OpenAFS::OS;
+use warnings;
+use strict;
+use OpenAFS::Dirpath;
+use OpenAFS::ConfigUtils;
+
+my $path = $OpenAFS::Dirpath::openafsdirpath;
+
+#
+# Create the named system object for OS specific init scripts
+# and commands.
+#
+sub create {
+ my $self = {
+ 'debug'=>0,
+ 'ostype'=>$path->{'ostype'},
+ @_,
+ };
+
+ my $class = _get_class($self->{'ostype'});
+ $self = bless($self, $class);
+ $self->{'commands'} = $self->get_commands();
+
+ # Put the paths to the cache and afsd into the path
+ # table. Assume legacy paths if the the viceetcdir is set to
+ # the Transarc path.
+ if ($path->{'viceetcdir'} eq '/usr/vice/etc') {
+ # set in the makefile dest targets
+ $path->{'cachedir'} = "/usr/vice" unless $path->{'cachedir'};
+ $path->{'afsddir'} = "/usr/vice/etc" unless $path->{'afsddir'};
+ }
+ else {
+ # set in the makefile install targets
+ $path->{'cachedir'} = "$path->{'localstatedir'}/openafs" unless $path->{'cachedir'};
+ $path->{'afsddir'} = "$path->{'afssrvsbindir'}" unless $path->{'afsddir'};
+ }
+
+ return $self;
+}
+
+#
+# _get_class(name) - Return the package name for the ostype
+#
+sub _get_class {
+ my $type = shift;
+ if ($type=~/linux/i) {
+ return "OpenAFS::OS::Linux";
+ }
+ die "error: Unknow system type. Valid types are: linux\n";
+}
+
+#
+# command(name [,params...]) - Return the command string or code reference.
+#
+sub command {
+ my $self = shift;
+ my $name = shift;
+ my $cmd = $self->{'commands'}->{$name};
+ unless (defined $cmd) {
+ die "error: Unsupported command name $name for OS type $self->{'ostype'}\n";
+ }
+ # add parameters if present.
+ if (scalar @_) {
+ if (ref($cmd) eq 'CODE') {
+ $cmd = sub { &$cmd(@_) };
+ }
+ else {
+ $cmd = join(' ', ($cmd, @_));
+ }
+ }
+ return $cmd;
+}
+
+#--------------------------------------------------------------
+# Common unix style os commands.
+package OpenAFS::OS::Unix;
+use warnings;
+use strict;
+use OpenAFS::ConfigUtils;
+use OpenAFS::Dirpath;
+our @ISA = qw(OpenAFS::OS);
+
+#
+# remove(target) - recursive remove
+#
+sub remove {
+ my $self = shift;
+ my $target = shift;
+ run("rm -rf $target");
+}
+
+#
+# Start the server.
+#
+sub fileserver_start {
+ my $self = shift;
+ run("$path->{'afssrvsbindir'}/bosserver");
+}
+
+#
+# Stop the server.
+#
+sub fileserver_stop {
+ my $self = shift;
+ my @bosserver_pids = $self->find_pids("bosserver");
+ if (scalar @bosserver_pids) {
+ # bosserver is running, try to shutdown with bos.
+ eval {
+ run("$path->{'afssrvbindir'}/bos shutdown localhost -localauth");
+ };
+ if ($@) {
+ warn "WARNING: Shutdown command failed.\n";
+ }
+ # Now shutdown bosserver process itself. Kill all of them
+ # in case there are remants.
+ foreach my $pid (@bosserver_pids) {
+ eval { run("kill $pid") };
+ }
+ }
+}
+
+#
+# Restart the server.
+#
+sub fileserver_restart {
+ my $self = shift;
+ fileserver_stop();
+ fileserver_start();
+}
+
+#
+# Return a list of pids.
+#
+sub find_pids {
+ my $self = shift;
+ my $process = shift;
+ my @pids = ();
+ my $ps = "ps -e -o pid,cmd";
+ if ($self->{'debug'}) {
+ print("debug: searching for process $process\n");
+ }
+ open(PS, "$ps |") or die "Cannot run command: $ps: $!";
+ while (<PS>) {
+ chomp;
+ my ($pid,$cmd) = split;
+ if ($cmd=~/$process/) {
+ if ($self->{'debug'}) {
+ print("debug: found $pid $cmd\n");
+ }
+ push(@pids, $pid);
+ }
+ }
+ close PS;
+ return @pids;
+}
+
+#--------------------------------------------------------------
+package OpenAFS::OS::Linux;
+use warnings;
+use strict;
+use OpenAFS::ConfigUtils;
+use OpenAFS::Dirpath;
+our @ISA = qw(OpenAFS::OS::Unix);
+
+#
+# OS-specific commands. Defer to init scripts where possible.
+#
+sub get_commands {
+ my $self = shift;
+ my $syscnf = "$path->{'initdir'}/testclient.conf";
+
+ my $commands = {
+ 'client-start' => "SYSCNF=$syscnf $path->{'initdir'}/afs.rc start",
+ 'client-stop' => "SYSCNF=$syscnf $path->{'initdir'}/afs.rc stop",
+ 'client-restart' => "SYSCNF=$syscnf $path->{'initdir'}/afs.rc restart",
+ 'client-forcestop' => sub { $self->client_forcestop() },
+ 'fileserver-start' => sub { $self->fileserver_start() },
+ 'fileserver-stop' => sub { $self->fileserver_stop() },
+ 'fileserver-restart' => sub { $self->fileserver_restart() },
+ 'remove' => 'rm -rf',
+ };
+ return $commands;
+}
+
+#
+# Setup the init script configuration, including the install paths.
+# Create the required directories for the client, /afs and the
+# cache directory.
+#
+# N.B.The cacheinfo file is created by the init script.
+#
+sub configure_client {
+ my $self = shift;
+ my $config = {
+ # defaults
+ 'cachesize' => '50000',
+ # custom
+ @_,
+ };
+
+ my $debug = $self->{'debug'};
+ my $syscnf = "$path->{'initdir'}/testclient.conf";
+
+ open (SYSCNF, "> $syscnf") or
+ die "error: Cannot open afs.rc configuration file $syscnf, $!\n";
+
+ print "debug: creating afs.rc configuration file $syscnf\n" if $debug;
+ print SYSCNF <<"_SYSCNF_";
+AFS_CLIENT=on
+AFS_SERVER=off
+ENABLE_AFSDB=off
+ENABLE_DYNROOT=off
+CACHESIZE=$config->{'cachesize'}
+OPTIONS="-confdir $path->{'viceetcdir'}"
+WAIT_FOR_SALVAGE=no
+AFSDIR=/afs
+CACHEDIR=$path->{'cachedir'}/cache
+CACHEINFO=$path->{'viceetcdir'}/cacheinfo
+VERBOSE=
+AFS_POST_INIT=
+AFSD=$path->{'afsddir'}/afsd
+BOSSERVER=$path->{'afssrvsbindir'}/bosserver
+BOS=$path->{'afssrvbindir'}/bos
+KILLAFS=$path->{'viceetcdir'}/killafs
+MODLOADDIR=$path->{'afskerneldir'}
+_SYSCNF_
+ close SYSCNF;
+ if ($debug) {
+ if (open(SYSCNF, "< $syscnf")) {
+ while (<SYSCNF>) {
+ chomp; print "debug: $_\n";
+ }
+ close SYSCNF;
+ }
+ }
+
+ # Create a cache directory if none.
+ unless ( -d "$path->{'cachedir'}/cache" ) {
+ print "debug: making cache directory: $path->{'cachedir'}/cache\n" if $debug;
+ system("mkdir -p $path->{'cachedir'}/cache");
+ system("chmod 0700 $path->{'cachedir'}/cache");
+ }
+
+ # Create the local /afs directory on which the afs filespace will be mounted.
+ if ( ! -d "/afs" ) {
+ print "debug: making the local /afs directory.\n" if $debug;
+ system("mkdir /afs");
+ system("chmod 0777 /afs");
+ }
+}
+
+#
+# Force the client to stop. The sequence is:
+# umount /afs
+# /usr/vice/etc/afsd -shutdown
+# rmmod openafs (or rmmod libafs)
+#
+sub client_forcestop {
+ my $self = shift;
+ print "debug: client forcestop\n" if $self->{'debug'};
+
+ eval {
+ run("umount /afs");
+ sleep 1;
+ };
+ eval {
+ run("$path->{'afsddir'}/afsd -shutdown");
+ sleep 1;
+ };
+
+ # Remove openafs modules still loaded.
+ my $mods = $self->list_modules();
+ if ($mods->{'openafs'}) {
+ eval { run("/sbin/rmmod openafs") };
+ }
+ if ($mods->{'libafs'}) {
+ eval { run("/sbin/rmmod libafs") };
+ }
+
+ # Check.
+ $mods = $self->list_modules();
+ if ($mods->{'openafs'}) {
+ print "warning: kernel module still loaded: openafs\n";
+ }
+ if ($mods->{'libafs'}) {
+ print "warning: kernel module still loaded: libafs\n";
+ }
+
+ # remove stale lock set by init script.
+ run("rm -f /var/lock/subsys/afs");
+}
+
+#
+# list_modules() - Returns a table of loaded module names.
+#
+sub list_modules {
+ my $self = shift;
+ my $mods = {};
+ if (open(LSMOD, "/sbin/lsmod |")) {
+ while(<LSMOD>) {
+ chomp;
+ my ($mod) = split;
+ $mods->{$mod} = 1;
+ }
+ close LSMOD;
+ }
+ return $mods;
+}
+
+1;
--- /dev/null
+#!/usr/bin/env perl
+#
+# Remove cell files from this machine. Use with caution!
+#
+
+use warnings;
+use strict;
+use OpenAFS::Dirpath;
+use OpenAFS::OS;
+use OpenAFS::ConfigUtils;
+use Term::ReadLine;
+use Getopt::Long;
+use Pod::Usage;
+
+=head1 NAME
+
+ afs-rmcell - Delete AFS cell files from this machine.
+
+=head1 SYNOPSIS
+
+B<afs-rmcell> [B<--batch>] [B<--partition-id>=letter] [B<--help>] [B<--debug>]
+
+=head1 DESCRIPTION
+
+This script destroys the AFS database and volume files on this machine.
+Use with caution!
+
+=cut
+
+my $debug = 0;
+my $help = 0;
+my $batch = 0;
+my $partition_id = 'a';
+my $path = $OpenAFS::Dirpath::openafsdirpath;
+my $ostype = $path->{'ostype'};
+
+#-----------------------------------------------------------------------------------
+# main script
+
+GetOptions(
+ "debug" => \$debug,
+ "help" => \$help,
+ "batch" => \$batch,
+ "partition-id=s" => \$partition_id,
+ "ostype=s" => \$ostype,
+);
+
+$OpenAFS::ConfigUtils::debug = $debug;
+
+if ($help) {
+ pod2usage(1);
+ exit 0;
+}
+
+if ($> != 0) {
+ die "error: This script should run as root.\n";
+}
+
+# To be on the safe side, we do no accept the full partition name, just the letter id.
+# You'll have to manually delete volume files for unconventional partition names.
+unless ($partition_id=~/^(([a-z])|([a-h][a-z])|([i][a-v]))$/) {
+ die "error: Invalid partition id specified.\n".
+ "info: Please specify a valid partition abbreviation, for example --partition-id='a' for /vicepa\n";
+}
+
+unless ($batch) {
+ my $rl = new Term::ReadLine('afs-rmcell');
+ print "\n*** WARNING!! WARNING!! WARNING!! *** \n";
+ print "You are about to permanently DESTROY the OpenAFS configuration, database, and volumes on this machine!\n\n";
+ my $answer = $rl->readline("Do you really want to destroy the AFS cell data? (y/n) [n] ");
+ unless ($answer=~/^y/i ) {
+ print "info: Aborted.\n";
+ exit 0;
+ }
+}
+
+my $os = OpenAFS::OS::create('ostype'=>$ostype, 'debug'=>$debug);
+
+# make sure the client init script has the correct paths.
+$os->configure_client();
+
+run($os->command('client-stop'));
+run($os->command('fileserver-stop'));
+run($os->command('client-forcestop'));
+
+$os->remove("$path->{'afsdbdir'}/prdb.DB0");
+$os->remove("$path->{'afsdbdir'}/prdb.DBSYS1");
+$os->remove("$path->{'afsdbdir'}/vldb.DB0");
+$os->remove("$path->{'afsdbdir'}/vldb.DBSYS1");
+$os->remove("$path->{'afsbosconfigdir'}/BosConfig");
+$os->remove("$path->{'afslogsdir'}/*");
+$os->remove("$path->{'afslocaldir'}/*");
+$os->remove("$path->{'afsconfdir'}/UserList");
+$os->remove("$path->{'afsconfdir'}/ThisCell");
+$os->remove("$path->{'afsconfdir'}/CellServDB");
+$os->remove("$path->{'afsconfdir'}/KeyFile");
+$os->remove("$path->{'afsconfdir'}/krb.conf");
+$os->remove("/vicep$partition_id/AFSIDat ");
+$os->remove("/vicep$partition_id/V*.vol");
+$os->remove("/vicep$partition_id/Lock");
+