#!/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

source /lib/apparmor/functions
source /lib/lsb/init-functions

proc 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

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

proc handle_system_policy_package_updates {
	setvar apparmor_was_updated = '0'

	if ! compare_previous_version  {
		# 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
		setvar apparmor_was_updated = '1'
	} elif ! compare_and_save_debsums apparmor  {
		# 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
		setvar apparmor_was_updated = '1'
	}

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

# Allow "recache" even when running on the liveCD
if test $1 = "recache" {
	log_daemon_msg "Recaching AppArmor profiles"
	recache_profiles
	setvar rc = ""$?
	log_end_msg $rc
	exit $rc
}

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

setvar rc = '255'
case (1) {
	start {
		if systemd-detect-virt --quiet --container && \
		   ! is_container_with_internal_policy {
			log_daemon_msg "Not starting AppArmor in container"
			log_end_msg 0
			exit 0
		}
		log_daemon_msg "Starting AppArmor profiles"
		securityfs
		handle_system_policy_package_updates
		load_configured_profiles
		setvar rc = ""$?
		log_end_msg $rc
		}
	stop {
		log_daemon_msg "Clearing AppArmor profiles cache"
		clear_cache
		setvar rc = ""$?
		log_end_msg $rc
		cat >&2 <<< """
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."
"""
		}
	teardown {
		if systemd-detect-virt --quiet --container && \
		   ! is_container_with_internal_policy {
			log_daemon_msg "Not tearing down AppArmor in container"
			log_end_msg 0
			exit 0
		}
		log_daemon_msg "Unloading AppArmor profiles"
		securityfs
		running_profile_names | while read profile {
			if ! unload_profile $profile  {
				log_end_msg 1
				exit 1
			}
		}
		setvar rc = '0'
		log_end_msg $rc
		}
	restart|reload|force-reload {
		if systemd-detect-virt --quiet --container && \
		   ! is_container_with_internal_policy {
			log_daemon_msg "Not reloading AppArmor in container"
			log_end_msg 0
			exit 0
		}
		log_daemon_msg "Reloading AppArmor profiles"
		securityfs
		clear_cache
		load_configured_profiles
		setvar rc = ""$?

		log_end_msg $rc
		}
	status {
		securityfs
		if test -x /usr/sbin/aa-status {
			aa-status --verbose
		} else {
			cat "$AA_SFS"/profiles
		}
		setvar rc = ""$?
		}
	* {
		usage
		setvar rc = '1'
		}
	}
exit $rc