#!/bin/sh
#
# remctl-acl-update -- Update remctl ACLs on local disk from pubsw.
#
# This script runs hourly from cron and copies remctl ACL files from AFS into
# /etc/remctl/acl.  This is a stop-gap measure until we have an LDAP-aware
# remctld that can use privilege groups directly.
#
# As a special case, it also generates a root-principal-only version of the
# systems ACL to use for remctl commands that are equivalent to having root.

# Exit on any errors.
set -e

# Some systems, most notably the Kerberos KDCs, have stricter requirements
# for who has root access.  On those systems, we don't want to update all
# of the ACLs from AFS since we'll give too many people access to
# root-equivalent commands like aptitude and puppet. The Kerberos KDCs
# also manage the "security" remctl ACL group, so we also skip that one.
# Detect those systems by seeing if there are admin instances in
# /root/.k5login and, if so, decline to update the operations and systems
# ACLs unless they're explicitly listed.
#
# Also don't update the operations and systems ACLs if they're the new-style
# ACLs that just include the appropriate its-idg or its-sysadmin ACLs.
acls="helpdesk-all its-idg its-idg-windows its-sysadmin its-sa-app its-sa-core its-sa-crc coreinfra as-cia as-linuxops"
acls="${acls} acs-linux its-sa-rc debian-repo-managers iedo"

# Add the "security" remctl ACL group only if we are NOT on a Kerberos KDC.
if [ -r /root/.k5login ] && ! grep -q '/admin@' /root/.k5login ; then
    acls="${acls} security"
fi

# If we're given any command-line arguments, copy those over instead.
if [ ! -z "$*" ] ; then
    acls="$*"
fi

# The path to the canonical files.  Note that ACL files in this directory will
# have .acl appended, but we strip that off when copying them to local disk.
source=/afs/ir.stanford.edu/pubsw/Local/config/share/etc/acl
if [ ! -d $source ] ; then
    exit 0
fi

# Copy over the ACL files.
for file in $acls ; do
    special='acs-linux|its-idg|its-idg-windows|its-sa-app|its-sa-core|its-sa-crc|its-sa-rc|its-sysadmin|networking|coreinfra|as-cia|as-linuxops|iedo'

    # Do not do anything unless source has changed, or acl is "special" and root
    # acl does not exist
    if ( cmp -s "$source/$file.acl" "/etc/remctl/acl/$file"     \
            && ! (echo "$file" | egrep -q "$special"))          \
        || (cmp -s "$source/$file.acl" "/etc/remctl/acl/$file"  \
            && (echo "$file" | egrep -q "$special")             \
            && [ -e "/etc/remctl/acl/$file-root" ] ) ; then
        :
    else
        cp --preserve=timestamps "$source/$file.acl" "/etc/remctl/acl/$file"
        if echo $file | egrep -q "$special"; then
            grep '/root@' /etc/remctl/acl/"$file" \
                > /etc/remctl/acl/"$file"-root
        fi
    fi
done

# Empty systems and operations ACLs, except keep systems and systems-root if
# they're includes of other, more appropriate ACL files.
if [ -r /root/.k5login ] && ! grep -q '/admin@' /root/.k5login ; then
    if ! grep -q '^file:' /etc/remctl/acl/systems 2> /dev/null ; then
        for file in systems systems-root ; do
            if [ -s "/etc/remctl/acl/$file" ] ; then
                rm "/etc/remctl/acl/$file"
                touch "/etc/remctl/acl/$file"
            fi
        done
    fi
    if [ -s /etc/remctl/acl/operations ] ; then
        rm /etc/remctl/acl/operations
        touch /etc/remctl/acl/operations
    fi
fi

exit 0

# Documentation.  Use a hack to hide this from the shell.  Because of the
# above exit line, this should never be executed.
DOCS=<<__END_OF_DOCS__

=for stopwords
ACL ACLs AFS Allbery acl remctl-acl-update helpdesk-all pubsw remctl
timestamps

=head1 NAME

remctl-acl-update - Update remctl ACLs on local disk from pubsw

=head1 SYNOPSIS

B<remctl-acl-update> [I<acl> ...]

=head1 DESCRIPTION

The default action is, for the list of ACLs specified at the beginning of
this shell script, check to see if the version in AFS is newer than the
version on local disk.  If so, copy the version from AFS to local disk,
preserving timestamps.

If ACLs are given on the command line, those files are copied instead of the
default set.  This allows adding an additional cron job to copy other ACLs
that a given server cares about without copying the same ACLs twice.

As a special case, this script also creates F<its-idg>, F<its-systems>,
and F<systems-root> ACL files, generated by extracting only root instances
from the corresponding ACL files without the C<-root> ending.

If there are admin instances in F</root/.k5login>, or if F</root/.k5login>
doesn't exist, this script removes the F<operations> and F<systems> ACLs
from the default set.  This is to prevent changing ACL files on systems
with more restricted access than normal.  It also declines to update the
F<operations> and F<systems> ACLs if the F<systems> ACL contains lines of
the form C<file:I<path>>, since it then assumes that those ACLs are
pointed at the appropriate group-specific ACLs instead of using the
general ACL.

=head1 EXAMPLES

To update the default set of ACLs, just run:

    remctl-acl-update

To update a specific ACL (whether one of the defaults or not), do:

    remctl-acl-update helpdesk-all

This will copy the helpdesk-all ACL from AFS.

=head1 FILES

=over 4

=item F</afs/ir.stanford.edu/pubsw/Local/config/share/etc/acl>

The directory in pubsw that is checked for newer copies of the ACLs.  If
this directory doesn't exist, the script exits quietly without changing
anything.  The ACLs in this directory are expected to end in C<.acl> but are
copied over without that extension.

=item F</etc/remctl/acl>

The local directory where the ACL files are stored.

=back

=head1 AUTHOR

Russ Allbery <rra@stanford.edu>

=cut

__END_OF_DOCS__
