alpine-linux-headless-boots.../overlay/etc/local.d/headless.start

248 lines
6.7 KiB
Bash
Executable File

#!/bin/sh
# Copyright 2022 - 2023, macmpi
# SPDX-License-Identifier: MIT
VERSION="0.8"
_apk() {
local cmd="$1"
local pkg="$2"
case $cmd in
add) # install only if not already present
if ! apk info | grep -wq "${pkg}"; then
apk add "$pkg" && printf "${pkg} " >> /tmp/.trash/installed
fi
;;
del) # delete only if previously installed
if grep -wq "$pkg" /tmp/.trash/installed; then
apk del "$pkg" && sed -i 's/\b'"${pkg}"'\b//' /tmp/.trash/installed
fi
;;
*)
echo "only add/del: wrong usage"; exit
;;
esac
}
_preserve() {
[ -f "$1" ] && cp "$1" "${1}.orig"
}
_restore() {
if [ -f "${1}.orig" ]; then
mv -- "${1}.orig" "${1}"
else
rm -rf "${1}"
fi
}
##### End of part to be duplicated into post-cleanup (do not alter!)
# Redirect stdout and errors to console as rc.local does not log anything
exec 1>/dev/console 2>&1
logger -st ${0##*/} "Alpine Linux headless bootstrap v$VERSION by macmpi"
install -dm 0700 /tmp/.trash
# grab used ovl filename from dmesg
ovl="$( dmesg | grep -o 'Loading user settings from .*:' | awk '{print $5}' | sed 's/:.*$//' )"
ovl="$( basename "${ovl}" )"
# search path again as mountpoint may have been changed later in the boot process...
ovlpath=$( find /media -maxdepth 2 -type d -path '*/.*' -prune -o -type f -name "${ovl}" -exec dirname {} \; | head -1 )
# Help randomness for wpa_supplicant and ssh server
rc-service seedrng start
## Setup Network interfaces
if [ -f "${ovlpath}/wpa_supplicant.conf" ]; then
logger -st ${0##*/} "Configuring wifi..."
_apk add wpa_supplicant
_preserve "/etc/wpa_supplicant/wpa_supplicant.conf"
install -m600 "${ovlpath}/wpa_supplicant.conf" /etc/wpa_supplicant/wpa_supplicant.conf
else
logger -st ${0##*/} "No wifi setup supplied !"
fi
_preserve "/etc/network/interfaces"
if ! install -m644 "${ovlpath}/interfaces" /etc/network/interfaces; then
# set default interfaces if not specified by interface file on boot storage
logger -st ${0##*/} "No interfaces file supplied, building defaults..."
for dev in $(ls /sys/class/net)
do
case ${dev%%[0-9]*} in
lo)
cat <<-EOF >> /etc/network/interfaces
auto $dev
iface $dev inet loopback
EOF
;;
eth)
cat <<-EOF >> /etc/network/interfaces
auto $dev
iface $dev inet dhcp
EOF
;;
wlan)
[ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && cat <<-EOF >> /etc/network/interfaces
auto $dev
iface $dev inet dhcp
EOF
;;
usb)
cat <<-EOF >> /etc/network/interfaces
auto $dev
iface $dev inet static
address 10.42.0.2/24
gateway 10.42.0.1
EOF
cat <<-EOF > /etc/resolv.conf
nameserver 208.67.222.222
nameserver 208.67.220.220
EOF
;;
esac
done
fi
echo "Using following network interfaces:"
cat /etc/network/interfaces
_preserve "/etc/hostname"
echo "alpine-headless" > /etc/hostname
hostname -F /etc/hostname
grep -q "wlan" /etc/network/interfaces && \
[ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && \
rc-service wpa_supplicant start
rc-service networking start
## Setup temporary SSH server (root login, no password)
## We use some bundled (or optionaly provided) keys to avoid generation at startup and save time
_apk add openssh
_preserve "/etc/ssh/sshd_config"
_preserve "/etc/conf.d/sshd"
cat <<-EOF > /etc/ssh/sshd_config
PermitRootLogin yes
Banner /tmp/.trash/banner
EOF
if install -m600 "${ovlpath}/authorized_keys" /tmp/.trash/authorized_keys; then
logger -st ${0##*/} "Enabling public key SSH authentication..."
cat <<-EOF >> /etc/ssh/sshd_config
AuthenticationMethods publickey
AuthorizedKeysFile /tmp/.trash/authorized_keys
# relax strict mode as authorized_keys are inside /tmp
StrictModes no
EOF
else
logger -st ${0##*/} "No SSH authentication."
cat <<-EOF >> /etc/ssh/sshd_config
AuthenticationMethods none
PermitEmptyPasswords yes
EOF
fi
# Banner file
warn=""
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
[ "$RO" -eq "0" ] && warn="(remount partition rw!)"
cat <<-EOF > /tmp/.trash/banner
Alpine Linux headless bootstrap v$VERSION by macmpi
You may want to delete/rename .apkovl file before reboot ${warn}:
${ovlpath}/${ovl}
(can be done automatically with unattended script - see sample snippet)
EOF
# Bundled temporary keys are moved in RAM /tmp so they won't be stored
# within permanent config later (new ones will then be generated at reboot)
KEYGEN_STANCE="sshd_disable_keygen=yes"
mv /etc/ssh/ssh_host_*_key* /tmp/.trash/.
# Inject optional custom keys (those might be stored)
if install -m600 "${ovlpath}"/ssh_host_*_key* /etc/ssh/; then
# check for empty key within injected ones: if found, generate new keys
if find /etc/ssh/ -maxdepth 1 -type f -name 'ssh_host_*_key*' -empty | grep -q .; then
rm /etc/ssh/ssh_host_*_key*
KEYGEN_STANCE=""
logger -st ${0##*/} "Will generate new SSH keys..."
else
chmod 644 /etc/ssh/ssh_host_*_key.pub
logger -st ${0##*/} "Using injected SSH keys..."
fi
else
logger -st ${0##*/} "Using bundled ssh keys from RAM..."
cat <<-EOF >> /etc/ssh/sshd_config
HostKey /tmp/.trash/ssh_host_ed25519_key
HostKey /tmp/.trash/ssh_host_rsa_key
EOF
fi
echo "$KEYGEN_STANCE" >> /etc/conf.d/sshd
rc-service sshd start
## Prep for final post-cleanup
## clears any installed packages and settings
# copy begininng of this file to keep functions
sed -n '/^#* End .*alter!)$/q;p' /etc/local.d/headless.start > /tmp/.trash/post-cleanup
cat <<-EOF >> /tmp/.trash/post-cleanup
_tst_inet() {
## Tested URL redirects to github project page: is.gd shortener provides basic analytics.
## Analytics are public and can be checked at https://is.gd/stats.php?url=apkovl_run
## Privacy policy: https://is.gd/privacy.php
INET="failed"
wget -q -T 10 --spider https://is.gd/apkovl_run > /dev/null 2>&1 &&
INET="success"
logger -st ${0##*/} "Internet access: \$INET"
}
logger -st ${0##*/} "Cleaning-up..."
_restore "/etc/ssh/sshd_config"
_restore "/etc/conf.d/sshd"
_apk del openssh
_restore "/etc/wpa_supplicant/wpa_supplicant.conf"
_apk del wpa_supplicant
_restore "/etc/network/interfaces"
_restore "/etc/hostname"
rm /etc/modules-load.d/g_ether.conf
rm /etc/modprobe.d/g_ether.conf
rc-update del local default
rm /etc/local.d/headless.start
# Internet connectivity test
# Can be skipped by creating a 'opt-out'-named dummy file aside apkovl file
[ -f "${ovlpath}/opt-out" ] || _tst_inet &
# Run unattended script if available
if [ -f "${ovlpath}/unattended.sh" ]; then
install -m755 "${ovlpath}/unattended.sh" /tmp/unattended.sh
/tmp/unattended.sh >/dev/console 2>&1 &
logger -st ${0##*/} "/tmp/unattended.sh script launched in the background with PID \$!"
fi
logger -st ${0##*/} "Done !!"
EOF
chmod +x /tmp/.trash/post-cleanup
exec /tmp/.trash/post-cleanup