# Semana 16: seguridad (permisos, setuid, ACLs, contraseñas).
#   make         compila todo
#   make test    crea usuarios y archivos en /tmp/w16 y corre cada programa
#                (pensado para el contenedor del curso, donde somos root)
#   make clean   borra los binarios
CFLAGS = -Wall -Wextra -g
PROGS  = perms ids hashpw crack timing
# Las soluciones aún no publicadas (code/.ocultos) no están en el repositorio:
# se omiten los programas sin fuente y sus líneas en las pruebas.
PROGS := $(foreach p,$(PROGS),$(if $(wildcard $(p).c),$(p)))
# Explotación y endurecimiento: cada binario se compila con banderas explícitas
# para que el resultado no dependa de los valores por defecto del compilador.
HARDEN = smash smash_ssp aslr aslr_nopie toctou
RUN    = $(if $(wildcard $(1).c),./$(1),@: sin $(1).c)
T      = /tmp/w16
# Ejecutar un comando como otro usuario, con sus grupos
AS     = setpriv --init-groups --reuid=$(1) --regid=$(1)
# Sin ASLR, para direcciones reproducibles
NOASLR = setarch -R

all: $(PROGS) $(HARDEN)

perms ids timing: %: %.c
	$(CC) $(CFLAGS) -o $@ $<

hashpw crack: %: %.c
	$(CC) $(CFLAGS) -o $@ $< -lcrypt

# smash: la misma fuente, una vez sin canario y otra con canario.
smash: smash.c
	$(CC) $(CFLAGS) -fno-stack-protector -no-pie -o $@ $<
smash_ssp: smash.c
	$(CC) $(CFLAGS) -fstack-protector-all -no-pie -o $@ $<

# aslr: con PIE (por defecto) y sin PIE, para ver qué agrega PIE.
aslr: aslr.c
	$(CC) $(CFLAGS) -fPIE -pie -o $@ $<
aslr_nopie: aslr.c
	$(CC) $(CFLAGS) -no-pie -o $@ $<

toctou: toctou.c
	$(CC) $(CFLAGS) -o $@ $<

# Usuarios ana y beto; grupo curso con ana. Tres archivos de prueba.
setup: perms ids
	rm -rf $(T)
	mkdir -p $(T)
	chmod 755 $(T)
	getent group curso >/dev/null || groupadd curso
	id ana  >/dev/null 2>&1 || useradd -M -G curso ana
	id beto >/dev/null 2>&1 || useradd -M beto
	echo "notas del curso" > $(T)/nota.txt
	chown ana:curso $(T)/nota.txt
	chmod 640 $(T)/nota.txt
	echo "solo root" > $(T)/secreto.txt
	chmod 600 $(T)/secreto.txt
	echo "raro" > $(T)/raro.txt
	chown ana:ana $(T)/raro.txt
	chmod 044 $(T)/raro.txt
	cp perms ids $(T)/
	chown root:root $(T)/ids
	chmod 4755 $(T)/ids

test: $(PROGS) setup
	@echo "--- permisos como root, ana y beto"
	./perms $(T)/nota.txt
	$(call AS,ana)  $(T)/perms $(T)/nota.txt $(T)/raro.txt
	$(call AS,beto) $(T)/perms $(T)/nota.txt
	@echo "--- ACL: dar lectura a beto sin tocar los bits"
	setfacl -m u:beto:r $(T)/nota.txt
	getfacl -c $(T)/nota.txt
	ls -l $(T)/nota.txt
	$(call AS,beto) $(T)/perms $(T)/nota.txt
	@echo "--- setuid root"
	ls -l $(T)/ids
	$(call AS,ana) $(T)/ids $(T)/secreto.txt
	@echo "--- contraseñas"
	$(call RUN,hashpw) alpaca
	$(call RUN,crack)
	@echo "--- comparación con fuga de tiempo"
	./timing
	@echo
	@$(MAKE) --no-print-directory testhard

# Explotación y endurecimiento, en el contenedor (seccomp=unconfined para setarch -R).
testhard: $(HARDEN)
	@mkdir -p $(T)
	@echo "=== buffer overflow en la pila"
	printf 'hola' > $(T)/in_ok
	head -c 30 /dev/zero | tr '\0' A > $(T)/in_overflow
	@echo "- sin canario, entrada corta:"
	$(NOASLR) ./smash $(T)/in_ok
	@echo "- sin canario, 30 bytes (pisa la dirección de retorno):"
	$(NOASLR) ./smash $(T)/in_overflow || true
	@echo "- con -fstack-protector, 30 bytes:"
	$(NOASLR) ./smash_ssp $(T)/in_overflow || true
	@echo "=== ASLR: direcciones en varias ejecuciones"
	@echo "- con PIE y ASLR (cambian entre corridas):"
	./aslr; ./aslr
	@echo "- con setarch -R (ASLR apagado: fijas):"
	$(NOASLR) ./aslr
	@echo "- sin PIE (-no-pie): código y datos fijos aunque ASLR siga activo:"
	./aslr_nopie
	@echo "=== TOCTOU: ganar la carrera con un enlace simbólico"
	@cd $(T); echo "decoy, lo pueden leer todos" > decoy.txt; echo "SECRETO" > target.txt; \
	  ( for i in $$(seq 1 60000); do ln -sfn decoy.txt link; ln -sfn target.txt link; done ) & \
	  atk=$$!; wins=0; \
	  for i in $$(seq 1 300); do \
	    r=$$($(CURDIR)/toctou vuln link 2>&1); \
	    case "$$r" in *TOCTOU*) wins=$$((wins+1)); [ $$wins -le 2 ] && echo "$$r";; esac; \
	  done; \
	  kill $$atk 2>/dev/null; wait 2>/dev/null; \
	  echo "  carreras ganadas: $$wins de 300"
	@echo "- versión segura (baja el euid al uid real + O_NOFOLLOW):"
	@cd $(T) && ln -sfn target.txt link && $(CURDIR)/toctou seguro link || true

clean:
	rm -f $(PROGS) $(HARDEN)

.PHONY: all setup test testhard clean
