#!/bin/sh
# ----------------------------------------------------------------------
#    Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
#     NOVELL (All rights reserved)
#    Copyright (c) 2008, 2009 Canonical, Ltd.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of version 2 of the GNU General Public
#    License published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, contact Novell, Inc.
# ----------------------------------------------------------------------
# Authors:
#  Steve Beattie <steve.beattie@canonical.com>
#  Kees Cook <kees@ubuntu.com>
#
# /etc/init.d/apparmor
#
### BEGIN INIT INFO
# Provides: apparmor
# Required-Start: $local_fs
# Required-Stop: umountfs
# Default-Start: S
# Default-Stop:
# Short-Description: AppArmor initialization
# Description: AppArmor init script. This script loads all AppArmor profiles.
### END INIT INFO

log_daemon_msg() {
    echo $*
}

log_end_msg () {
    retval=$1
    if [ $retval -eq 0 ]; then
        echo "."
    else
        echo " failed!"
    fi
    return $retval
}

. /lib/apparmor/functions
. /lib/lsb/init-functions

usage() {
    echo "Usage: $0 {start|stop|restart|reload|force-reload|status|recache}"
}

test -x ${PARSER} || exit 0 # by debian policy
# LSM is built-in, so it is either there or not enabled for this boot
test -d /sys/module/apparmor || exit 0

securityfs() {
	# Need securityfs for any mode
	if [ ! -d "${AA_SFS}" ]; then
		if cut -d" " -f2,3 /proc/mounts | grep -q "^${SECURITYFS} securityfs"'$' ; then
			log_daemon_msg "AppArmor not available as kernel LSM."
			log_end_msg 1
			exit 1
		else
			log_daemon_msg "Mounting securityfs on ${SECURITYFS}"
			if ! mount -t securityfs none "${SECURITYFS}"; then
				log_end_msg 1
				exit 1
			fi
		fi
	fi
	if [ ! -w "$AA_SFS"/.load ]; then
		log_daemon_msg "Insufficient privileges to change profiles."
		log_end_msg 1
		exit 1
	fi
}

handle_system_policy_package_updates() {
	apparmor_was_updated=0

	if ! compare_previous_version ; then
		# On snappy flavors, if the current and previous versions are
		# different then clear the system cache. snappy will handle
		# "$PROFILES_CACHE_VAR" itself (on Touch flavors
		# compare_previous_version always returns '0' since snappy
		# isn't available).
		clear_cache_system
		apparmor_was_updated=1
	elif ! compare_and_save_debsums apparmor ; then
		# If the system policy has been updated since the last time we
		# ran, clear the cache to prevent potentially stale binary
		# cache files after an Ubuntu image based upgrade (LP:
		# #1350673). This can be removed once all system image flavors
		# move to snappy (on snappy systems compare_and_save_debsums
		# always returns '0' since /var/lib/dpkg doesn't exist).
		clear_cache
		apparmor_was_updated=1
	fi

	if [ -x /usr/bin/aa-clickhook ] || [ -x /usr/bin/aa-profile-hook ] ; then
		# If packages for system policy that affect click packages have
		# been updated since the last time we ran, run aa-clickhook -f
                force_clickhook=0
                force_profile_hook=0
                if ! compare_and_save_debsums apparmor-easyprof-ubuntu ; then
                        force_clickhook=1
                fi
                if ! compare_and_save_debsums apparmor-easyprof-ubuntu-snappy ; then
                        force_clickhook=1
                fi
                if ! compare_and_save_debsums click-apparmor ; then
                        force_clickhook=1
                        force_profile_hook=1
                fi
                if [ -x /usr/bin/aa-clickhook ] && ([ $force_clickhook -eq 1 ] || [ $apparmor_was_updated -eq 1 ]) ; then
                        aa-clickhook -f
                fi
                if [ -x /usr/bin/aa-profile-hook ] && ([ $force_profile_hook -eq 1 ] || [ $apparmor_was_updated -eq 1 ]) ; then
                        aa-profile-hook -f
                fi
	fi
}

# Allow "recache" even when running on the liveCD
if [ "$1" = "recache" ]; then
	log_daemon_msg "Recaching AppArmor profiles"
	recache_profiles
	rc=$?
	log_end_msg "$rc"
	exit $rc
fi

# do not perform start/stop/reload actions when running from liveCD
test -d /rofs/etc/apparmor.d && exit 0

rc=255
case "$1" in
	start)
		if test -x /sbin/systemd-detect-virt && \
		   systemd-detect-virt --quiet --container && \
		   ! is_container_with_internal_policy; then
			log_daemon_msg "Not starting AppArmor in container"
			log_end_msg 0
			exit 0
		fi
		log_daemon_msg "Starting AppArmor profiles"
		securityfs
		# That is only useful for click, snappy and system images,
		# i.e. not in Debian. And it reads and writes to /var, that
		# can be remote-mounted, so it would prevent us from using
		# Before=sysinit.target without possibly introducing dependency
		# loops.
		handle_system_policy_package_updates
		load_configured_profiles
		rc=$?
		log_end_msg "$rc"
		;;
	stop)
		log_daemon_msg "Clearing AppArmor profiles cache"
		clear_cache
		rc=$?
		log_end_msg "$rc"
		cat >&2 <<EOM
All profile caches have been cleared, but no profiles have been unloaded.
Unloading profiles will leave already running processes permanently
unconfined, which can lead to unexpected situations.

To set a process to complain mode, use the command line tool
'aa-complain'. To really tear down all profiles, run the init script
with the 'teardown' option."
EOM
		;;
	teardown)
		if test -x /sbin/systemd-detect-virt && \
		   systemd-detect-virt --quiet --container && \
		   ! is_container_with_internal_policy; then
			log_daemon_msg "Not tearing down AppArmor in container"
			log_end_msg 0
			exit 0
		fi
		log_daemon_msg "Unloading AppArmor profiles"
		securityfs
		running_profile_names | while read profile; do
			if ! unload_profile "$profile" ; then
				log_end_msg 1
				exit 1
			fi
		done
		rc=0
		log_end_msg $rc
		;;
	restart|reload|force-reload)
		if test -x /sbin/systemd-detect-virt && \
		   systemd-detect-virt --quiet --container && \
		   ! is_container_with_internal_policy; then
			log_daemon_msg "Not reloading AppArmor in container"
			log_end_msg 0
			exit 0
		fi
		log_daemon_msg "Reloading AppArmor profiles"
		securityfs
		clear_cache
		load_configured_profiles
		rc=$?
		unload_obsolete_profiles

		log_end_msg "$rc"
		;;
	status)
		securityfs
		if [ -x /usr/sbin/aa-status ]; then
			aa-status --verbose
		else
			cat "$AA_SFS"/profiles
		fi
		rc=$?
		;;
	*)
		usage
		rc=1
		;;
	esac
exit $rc
