#
# Makefile for the security policy.
#
# Targets:
# 
# install - compile and install the policy configuration.
# load    - compile, install, and load the policy configuration.
# reload  - compile, install, and load/reload the policy configuration.
# relabel - relabel filesystems based on the file contexts configuration.
# policy  - compile the policy configuration locally for testing/development.
#
# The default target is 'install'.
#

# Set to y if MLS is enabled in the module.
MLS=n

FLASKDIR = flask/
PREFIX = /usr
BINDIR = $(PREFIX)/bin
SBINDIR = $(PREFIX)/sbin
LOADPOLICY  = $(SBINDIR)/load_policy
CHECKPOLICY = $(BINDIR)/checkpolicy
SETFILES = $(SBINDIR)/setfiles
POLICYVER := policy.$(shell $(CHECKPOLICY) $(POLICYCOMPAT) -V |cut -f 1 -d ' ')
INSTALLDIR = $(DESTDIR)/etc/security/selinux
LOADPATH = $(INSTALLDIR)/$(POLICYVER)
FCPATH = $(INSTALLDIR)/file_contexts
SRCINSTALLDIR = $(INSTALLDIR)/src

ALL_PROGRAM_MACROS := $(wildcard macros/program/*.te)
ALL_MACROS := $(ALL_PROGRAM_MACROS) $(wildcard macros/*.te)
ALL_TYPES := $(wildcard types/*.te)
ALL_DOMAINS := $(wildcard domains/*.te domains/misc/*.te domains/program/*.te)
ALLTEFILES := attrib.te tmp/program_used_flags.te $(ALL_MACROS) $(ALL_TYPES) $(ALL_DOMAINS) assert.te 
TE_RBAC_FILES := $(ALLTEFILES) rbac

POLICYFILES = $(addprefix $(FLASKDIR),security_classes initial_sids access_vectors)
ifeq ($(MLS),y)
POLICYFILES += mls
endif
POLICYFILES += tunable.te $(TE_RBAC_FILES)
POLICYFILES += users serviceusers
POLICYFILES += constraints initial_sid_contexts fs_use genfs_contexts net_contexts

UNUSED_TE_FILES := $(wildcard domains/program/unused/*.te)

FC = file_contexts/file_contexts
FCFILES=file_contexts/types.fc $(wildcard file_contexts/misc/*.fc) $(patsubst domains/program/%.te,file_contexts/program/%.fc, $(wildcard domains/program/*.te))

APPDIR=$(DESTDIR)/etc/security
APPFILES = $(addprefix $(APPDIR)/,default_contexts default_type initrc_context failsafe_context)
ROOTDIR=$(DESTDIR)/root
ROOTFILES = $(addprefix $(ROOTDIR)/,.default_contexts)

install: $(APPFILES) $(ROOTFILES) $(LOADPATH) $(FCPATH) 

$(APPDIR)/default_contexts: appconfig/default_contexts
	install -m 644 $< $@

$(APPDIR)/default_type: appconfig/default_type
	install -m 644 $< $@

$(APPDIR)/initrc_context: appconfig/initrc_context
	install -m 644 $< $@

$(APPDIR)/failsafe_context: appconfig/failsafe_context
	install -m 644 $< $@

$(ROOTDIR)/.default_contexts: appconfig/root_default_contexts
	install -m 644 $< $@


$(LOADPATH):  policy.conf $(CHECKPOLICY)
	mkdir -p $(INSTALLDIR)
	$(CHECKPOLICY) -o $@ policy.conf
# Note: Can't use install, so not sure how to deal with mode, user, and group
#	other than by default.

policy: $(POLICYVER)

$(POLICYVER):  policy.conf $(CHECKPOLICY)
	$(CHECKPOLICY) -o $@ policy.conf

reload tmp/load: $(LOADPATH) $(FCPATH) 
	$(LOADPOLICY) $(INSTALLDIR)/policy.`cat /selinux/policyvers`
	touch tmp/load

load: tmp/load

enableaudit: policy.conf 
	grep -v dontaudit policy.conf > policy.audit
	mv policy.audit policy.conf

policy.conf: $(POLICYFILES) 
	mkdir -p tmp
	m4 $(M4PARAM) -Imacros -s $^ > $@.tmp
	mv $@.tmp $@

install-src: 
	rm -rf $(SRCINSTALLDIR)/policy.old
	-mv $(SRCINSTALLDIR)/policy $(SRCINSTALLDIR)/policy.old
	mkdir -p $(SRCINSTALLDIR)/policy
	cp -R . $(SRCINSTALLDIR)/policy

tmp/program_used_flags.te: $(wildcard domains/program/*.te) domains/program
	mkdir -p tmp
	( cd domains/program/ ; for n in *.te ; do echo "define(\`$$n')"; done ) > $@.tmp
	( cd domains/misc/ ; for n in *.te ; do echo "define(\`$$n')"; done ) >> $@.tmp
	mv $@.tmp $@

checklabels: $(SETFILES)
	$(SETFILES) -v -n $(FC) `mount | grep -v "context=" | egrep -v '\((|.*,)bind(,.*|)\)' | awk '/(ext[23]| xfs).*rw/{print $$3}';`

restorelabels: $(SETFILES)
	$(SETFILES) -v $(FC) `mount | grep -v "context=" | egrep -v '\((|.*,)bind(,.*|)\)' | awk '/(ext[23]| xfs).*rw/{print $$3}';`

relabel:  $(FC) $(SETFILES)
	@echo "Cleaning out /tmp"
	-rm -rf /tmp/.??* /tmp/*
	$(SETFILES) $(FC) `mount | grep -v "context=" | egrep -v '\((|.*,)bind(,.*|)\)' | awk '/(ext[23]| xfs).*rw/{print $$3}';`

file_contexts/misc:
	mkdir -p file_contexts/misc

$(FCPATH): $(FC) 
	@mkdir -p $(INSTALLDIR)
	install -m 644 $(FC) $(FCPATH)

$(FC): $(FCFILES) domains/program domains/misc file_contexts/program file_contexts/misc users
	@echo "Building file_contexts ..."
	@m4 $(FCFILES) > $@.tmp
	@grep -v "^/root" $@.tmp > $@.root
	@/usr/sbin/genhomedircon . $@.root  > $@
	@grep "^/root" $@.tmp >> $@
	@-rm $@.tmp $@.root

clean:
	rm -f policy.conf
	rm -f tmp/*
	rm -f $(FC)
# for the policy regression tester
	find "domains/program/" -maxdepth 1 -type l -exec rm {} \; ; \

# Policy regression tester.
# Written by Colin Walters <walters@debian.org>
cur_te = $(filter-out %/,$(subst /,/ ,$@))

TESTED_TE_FILES := $(notdir $(UNUSED_TE_FILES))

define compute_depends
  export TE_DEPENDS_$(1) := $(shell egrep '^#[[:space:]]*Depends: ' domains/program/unused/$(1) | head -1 | sed -e 's/^.*Depends: //')
endef


ifeq ($(TE_DEPENDS_DEFINED),)
ifeq ($(MAKECMDGOALS),check-all)
  GENRULES := $(TESTED_TE_FILES)
  export TE_DEPENDS_DEFINED := yes
else
  # Handle the case where checkunused/blah.te is run directly.
  ifneq ($(findstring checkunused/,$(MAKECMDGOALS)),)
    GENRULES := $(TESTED_TE_FILES)
    export TE_DEPENDS_DEFINED := yes
  endif
endif
endif

# Test for a new enough version of GNU Make.
$(eval have_eval := yes)
ifneq ($(GENRULES),)
  ifeq ($(have_eval),)
$(error Need GNU Make 3.80 or better!)
Need GNU Make 3.80 or better
  endif
endif
$(foreach f,$(GENRULES),$(eval $(call compute_depends,$(f))))

PHONIES :=

define compute_presymlinks
PHONIES += presymlink/$(1)
presymlink/$(1):: $(patsubst %,presymlink/%,$(TE_DEPENDS_$(1)))
	@if ! test -L domains/program/$(1); then \
	  cd domains/program && ln -s unused/$(1) .; \
	fi
endef

# Compute dependencies.
$(foreach f,$(TESTED_TE_FILES),$(eval $(call compute_presymlinks,$(f))))

PHONIES += $(patsubst %,checkunused/%,$(TESTED_TE_FILES))
$(patsubst %,checkunused/%,$(TESTED_TE_FILES)) :: checkunused/% : 
	@$(MAKE) -s clean

$(patsubst %,checkunused/%,$(TESTED_TE_FILES)) :: checkunused/% : presymlink/%
	@if test -n "$(TE_DEPENDS_$(cur_te))"; then \
	  echo "Dependencies for $(cur_te): $(TE_DEPENDS_$(cur_te))"; \
	fi
	@echo "Testing $(cur_te)...";
	@if ! make -s policy 1>/dev/null; then \
	  echo "Testing $(cur_te)...FAILED"; \
	  exit 1; \
	fi;
	@echo "Testing $(cur_te)...success."; \

check-all:
	@for goal in  $(patsubst %,checkunused/%,$(TESTED_TE_FILES)); do \
	  $(MAKE) --no-print-directory $$goal; \
	done

.PHONY: clean $(PHONIES)
