134 lines
4 KiB
Text
134 lines
4 KiB
Text
|
|
#!/bin/sh
|
||
|
|
# Clawdie operator USB live seed importer.
|
||
|
|
# Reads operator-provided files from the FAT32 CLAWDIESEED partition
|
||
|
|
# (mountable on Linux pre-flash) and installs them into the live system
|
||
|
|
# at every boot. Idempotent by design: editing the seed and rebooting
|
||
|
|
# re-applies it. Failure is never fatal — missing/empty/unmountable seed
|
||
|
|
# logs and continues so the operator can still log in via SDDM.
|
||
|
|
#
|
||
|
|
# Runs before LOGIN so sshd sees the imported authorized_keys on first
|
||
|
|
# attach. See live/operator-session/clawdie-live-seed.README.txt for the
|
||
|
|
# allowlisted file contract written to the FAT at build time.
|
||
|
|
|
||
|
|
# PROVIDE: clawdie_live_seed
|
||
|
|
# REQUIRE: FILESYSTEMS devfs
|
||
|
|
# BEFORE: LOGIN
|
||
|
|
# KEYWORD: nojail
|
||
|
|
|
||
|
|
. /etc/rc.subr
|
||
|
|
|
||
|
|
name="clawdie_live_seed"
|
||
|
|
rcvar="${name}_enable"
|
||
|
|
start_cmd="${name}_start"
|
||
|
|
stop_cmd=":"
|
||
|
|
# This service is one-shot/idempotent, not a daemon — the default
|
||
|
|
# rc.subr status check looks for a pidfile and would say "not running"
|
||
|
|
# even after a successful import, which is actively misleading. Override
|
||
|
|
# with a log-tail report so `service clawdie_live_seed status` answers
|
||
|
|
# the question the operator is actually asking ("did the import run?").
|
||
|
|
status_cmd="${name}_status"
|
||
|
|
extra_commands="status"
|
||
|
|
|
||
|
|
SEED_LABEL="CLAWDIESEED"
|
||
|
|
SEED_MOUNT="/mnt/clawdie-seed"
|
||
|
|
SEED_LOG="/var/log/clawdie-live-seed.log"
|
||
|
|
SEED_USER="clawdie"
|
||
|
|
SEED_USER_HOME="/home/clawdie"
|
||
|
|
|
||
|
|
_seed_log() {
|
||
|
|
printf '%s %s\n' "$(date '+%Y-%m-%dT%H:%M:%S')" "$1" >>"${SEED_LOG}" 2>/dev/null || true
|
||
|
|
}
|
||
|
|
|
||
|
|
_seed_find_partition() {
|
||
|
|
for _candidate in \
|
||
|
|
"/dev/msdosfs/${SEED_LABEL}" \
|
||
|
|
"/dev/gpt/${SEED_LABEL}" \
|
||
|
|
"/dev/label/${SEED_LABEL}"
|
||
|
|
do
|
||
|
|
if [ -e "${_candidate}" ]; then
|
||
|
|
echo "${_candidate}"
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
|
||
|
|
if command -v gpart >/dev/null 2>&1; then
|
||
|
|
gpart show -lp 2>/dev/null \
|
||
|
|
| awk -v label="${SEED_LABEL}" '
|
||
|
|
$0 ~ label {
|
||
|
|
for (i = 1; i <= NF; i++) {
|
||
|
|
if ($i ~ "^/dev/") { print $i; exit }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
'
|
||
|
|
fi
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
|
||
|
|
_seed_install_authorized_keys() {
|
||
|
|
_src="$1"
|
||
|
|
|
||
|
|
_ssh_dir="${SEED_USER_HOME}/.ssh"
|
||
|
|
_dst="${_ssh_dir}/authorized_keys"
|
||
|
|
|
||
|
|
mkdir -p "${_ssh_dir}"
|
||
|
|
chown "${SEED_USER}:${SEED_USER}" "${_ssh_dir}" 2>/dev/null || true
|
||
|
|
chmod 0700 "${_ssh_dir}"
|
||
|
|
|
||
|
|
# Strip CRLF so keys created on Windows/Linux editors don't get rejected
|
||
|
|
# by sshd for trailing whitespace.
|
||
|
|
tr -d '\r' <"${_src}" >"${_dst}.new"
|
||
|
|
mv -f "${_dst}.new" "${_dst}"
|
||
|
|
chown "${SEED_USER}:${SEED_USER}" "${_dst}" 2>/dev/null || true
|
||
|
|
chmod 0600 "${_dst}"
|
||
|
|
|
||
|
|
_seed_log "installed authorized_keys from ${_src} -> ${_dst}"
|
||
|
|
}
|
||
|
|
|
||
|
|
clawdie_live_seed_start() {
|
||
|
|
: >>"${SEED_LOG}" 2>/dev/null || true
|
||
|
|
|
||
|
|
_dev=$(_seed_find_partition)
|
||
|
|
if [ -z "${_dev:-}" ]; then
|
||
|
|
_seed_log "no ${SEED_LABEL} partition found — skipping import"
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
mkdir -p "${SEED_MOUNT}"
|
||
|
|
if ! mount -t msdosfs -o ro "${_dev}" "${SEED_MOUNT}" 2>>"${SEED_LOG}"; then
|
||
|
|
_seed_log "mount failed on ${_dev} — skipping import"
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Allowlist: /ssh/authorized_keys takes precedence over /authorized_keys.
|
||
|
|
# Any other file on the partition is ignored on purpose.
|
||
|
|
_imported=0
|
||
|
|
if [ -f "${SEED_MOUNT}/ssh/authorized_keys" ]; then
|
||
|
|
_seed_install_authorized_keys "${SEED_MOUNT}/ssh/authorized_keys"
|
||
|
|
_imported=1
|
||
|
|
elif [ -f "${SEED_MOUNT}/authorized_keys" ]; then
|
||
|
|
_seed_install_authorized_keys "${SEED_MOUNT}/authorized_keys"
|
||
|
|
_imported=1
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [ "${_imported}" -eq 0 ]; then
|
||
|
|
_seed_log "no allowlisted files on ${_dev} — nothing to import"
|
||
|
|
fi
|
||
|
|
|
||
|
|
umount "${SEED_MOUNT}" 2>/dev/null || true
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
|
||
|
|
clawdie_live_seed_status() {
|
||
|
|
if [ -s "${SEED_LOG}" ]; then
|
||
|
|
echo "${name}: one-shot importer; last run log tail:"
|
||
|
|
tail -n 5 "${SEED_LOG}"
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
echo "${name}: not yet run this boot (no log at ${SEED_LOG})"
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
|
||
|
|
load_rc_config "$name"
|
||
|
|
: "${clawdie_live_seed_enable:=YES}"
|
||
|
|
run_rc_command "$1"
|