#!/usr/bin/perl -w
$ID = q$Id: afs-backend-acl,v 1.6 2005/06/19 03:23:14 eagle Exp $;
#
# afs-backend-acl -- Generate remctl ACL files for afs-backend.
#
# Written by Russ Allbery <rra@stanford.edu>
# Copyright 2002, 2003, 2005 Board of Trustees, Leland Stanford Jr. University
#
# This script generates, from the afs-backend ACL file, remctl ACL files that
# just list all the Kerberos principals of anyone who could possibly do
# anything with the afs-backend script.

##############################################################################
# Site configuration
##############################################################################

# The ACL file for afs-backend.
$ACL            = '/db/afsdb/acl/afs-backend';

# The paths to the sysctl and remctl ACL files.
$REMCTL         = '/etc/leland/remctl/afs.acl';

# The domain name, which should be appended to unqualified hostnames to form
# complete host/* principal names.
$DOMAIN         = 'stanford.edu';

# The realm name, which should be appended to a principal to form a complete
# identifier.
$K5_REALM       = 'stanford.edu';

# The full path to pts.
($PTS) = grep { -x $_ } qw(/usr/bin/pts /usr/pubsw/bin/pts);
$PTS ||= '/usr/pubsw/bin/pts';

##############################################################################
# Modules and declarations
##############################################################################

require 5.005;

use strict;
use vars qw($ACL $DOMAIN $ID $K5_REALM $PTS $REMCTL);

##############################################################################
# ACL parsing
##############################################################################

# Given a PTS group, expand it out into its members.
sub pts_expand {
    my ($group) = @_;
    die "$0: invalid group $group" if $group =~ /[\\\']/;
    my @output = `$PTS membership '$group' -noauth`;
    if ($? != 0) {
        warn "$0: $PTS membership on $group failed\n";
        return;
    } else {
        shift @output;
        for (@output) {
            s/^\s*//;
            s/\s*$//;
        }
        return @output;
    }
}

# Returns the list of users that may possibly be allowed to do something by
# afs-backend.  Eliminate duplicates and return a sorted list.
sub acl_expand {
    my @users;
    open ACL or die "$0: cannot open $ACL: $!\n";
    local $_;
    while (<ACL>) {
        next if /^\s*\#/;
        next if /^\s*$/;
        my @acl = split;
        next unless @acl > 2;
        push (@users, map { /:/ ? pts_expand ($_) : ($_) } @acl[2..$#acl]);
    }
    close ACL;
    my %users = map { $_ => 1 } @users;
    return sort keys %users;
}

##############################################################################
# ACL generation
##############################################################################

# Given an open file handle and a list of users, write out a sysctl ACL
# containing those users to that file handle.
sub remctl_acl_write {
    my ($fh, @users) = @_;
    for (@users) {
        tr%.%/%;
        s%^rcmd/%host/%;
        if (m%^(host|webauth)/([^.]+)$%) {
            $_ = "$1/$2.$DOMAIN";
        }
        print $fh "$_\@$K5_REALM\n";
    }
}

##############################################################################
# Main routine
##############################################################################

# Clean up $0 for error messages.
$0 =~ s%.*/%%;

# Write a remctl ACL to /etc/leland/remctl/afs.acl.
my @users = acl_expand;
open (OUT, "> $REMCTL") or die "$0: cannot create $REMCTL: $!\n";
remctl_acl_write (\*OUT, @users);
close OUT;
exit 0;

__END__

##############################################################################
# Documentation
##############################################################################

=head1 NAME

afs-backend-acl - Generate a remctl ACL from the afs-backend ACL

=head1 SYNOPSIS

B<afs-backend-acl> [I<output>]

=head1 DESCRIPTION

The B<afs-backend> program has its own ACL file that specifies exactly what
each user can do, and can also take PTS groups instead of just lists of users.
This is more precise than the remctl ACL file is capable of being, but for
security we also want to limit the ability to even run that script to only
those people who could actually do something with it.

This script generates, from the B<afs-backend> ACL file, a remctl ACL files
that just lists all the Kerberos principals of anyone who could possibly do
anything with the B<afs-backend> script.

=head1 FILES

=over 4

=item F</db/afsdb/acl/afs-backend>

The expected location of the ACL file describing which users have which
volume release and creation permissions, as described in L<DESCRIPTION>
above.

=item F</etc/leland/remctl/afs.acl>

The location to which the remctl ACL file is written.

=back

=head1 AUTHOR

Russ Allbery <rra@stanford.edu>

=head1 COPYRIGHT AND LICENSE

Copyright 2002, 2003, 2005 Board of Trustees, Leland Stanford
Jr. University.

This program is free software; you may redistribute it and/or modify it
under the same terms as Perl itself.

=head1 SEE ALSO

afs-backend(1), pts(1)

The current version of this program is available from the B<afs-backend> web
page at L<http://www.eyrie.org/~eagle/software/afs-backend/>.

=cut