diff --git a/Dockerfile b/Dockerfile index acab8ba..a819c0e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,31 @@ -FROM debian:bookworm-slim +FROM ubuntu:22.04 ENV DEBIAN_FRONTEND=noninteractive -# Install packages +# Install base packages and enable the dosemu2 PPA RUN apt-get update && \ apt-get install -y --no-install-recommends \ + software-properties-common \ + gnupg \ openssh-server \ - dosemu2 \ - dosbox-staging \ busybox-static \ sudo \ ca-certificates \ curl \ + mtools \ + unzip \ + file \ + && add-apt-repository -y ppa:dosemu2/ppa && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + dosemu2 \ && rm -rf /var/lib/apt/lists/* -# Provide DOS wrapper and service supervisor -COPY dos-shell /usr/local/bin/dos-shell -COPY start-services.sh /usr/local/bin/start-dos-services -RUN chmod +x /usr/local/bin/dos-shell /usr/local/bin/start-dos-services && \ +# Provide DOS wrapper, SvarDOS bootstrapper, and service supervisor +COPY scripts/dos-shell /usr/local/bin/dos-shell +COPY scripts/prepare-svardos.sh /usr/local/bin/prepare-svardos +COPY scripts/start-services.sh /usr/local/bin/start-dos-services +RUN chmod +x /usr/local/bin/dos-shell /usr/local/bin/start-dos-services /usr/local/bin/prepare-svardos && \ echo "/usr/local/bin/dos-shell" >> /etc/shells # Create sshd runtime directory @@ -29,14 +37,20 @@ RUN useradd -m -s /usr/local/bin/dos-shell dosuser && \ echo "dosuser:dosuser" | chpasswd # Create directories for allowed DOS files and the C: drive mount -RUN mkdir -p /opt/allowed_repo /cdrive /etc/dos_env && \ +RUN mkdir -p /opt/allowed_repo /cdrive /etc/dos_env /opt/svardos && \ chown -R dosuser:dosuser /opt/allowed_repo /cdrive +# Download and stage SvarDOS base files +ARG SVARDOS_IMG_URL +ENV SVARDOS_IMG_URL=${SVARDOS_IMG_URL} +RUN /usr/local/bin/prepare-svardos && \ + chown -R dosuser:dosuser /opt/svardos + # Default allowed list (can be overridden with a bind mount) -COPY dos_allowed /etc/dos_allowed +COPY config/dos_allowed /etc/dos_allowed # Configure sshd to force command for dosuser -COPY sshd_config /etc/ssh/sshd_config +COPY config/sshd_config /etc/ssh/sshd_config EXPOSE 22 23 CMD ["/usr/local/bin/start-dos-services"] diff --git a/allowed_repo/.gitkeep b/allowed_repo/.gitkeep new file mode 100644 index 0000000..908fcff --- /dev/null +++ b/allowed_repo/.gitkeep @@ -0,0 +1 @@ +*** End Patch diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..b2573ec --- /dev/null +++ b/compose.yml @@ -0,0 +1,21 @@ +services: + dos: + build: + context: . + args: + SVARDOS_IMG_URL: ${SVARDOS_IMG_URL:-} + image: ${DOS_IMAGE_NAME:-dos-env} + container_name: ${DOS_CONTAINER_NAME:-dos-env} + ports: + - "${DOS_SSH_PORT:-2222}:22" + - "${DOS_TELNET_PORT:-2323}:23" + environment: + DOS_ALLOW_MODE: ${DOS_ALLOW_MODE:-all} + ENABLE_TELNET: ${ENABLE_TELNET:-1} + TELNET_PORT: ${TELNET_PORT:-23} + TELNET_LOGIN: /bin/login + volumes: + - ./allowed_repo:/opt/allowed_repo + - ./config/dos_allowed:/etc/dos_allowed:ro + - ./dos_env:/etc/dos_env + restart: unless-stopped diff --git a/dos_allowed b/config/dos_allowed similarity index 100% rename from dos_allowed rename to config/dos_allowed diff --git a/sshd_config b/config/sshd_config similarity index 100% rename from sshd_config rename to config/sshd_config diff --git a/dos_env/README.md b/dos_env/README.md new file mode 100644 index 0000000..89da40b --- /dev/null +++ b/dos_env/README.md @@ -0,0 +1,8 @@ +# DOS Environment Templates + +Place optional template files here to customize the boot process: + +- `AUTOEXEC.BAT` – copied verbatim to `C:\AUTOEXEC.BAT` on each login. +- `CONFIG.SYS` – copied to `C:\CONFIG.SYS` on each login. + +Leave this directory empty to use the defaults generated by `dos-shell`. diff --git a/dos-shell b/scripts/dos-shell similarity index 51% rename from dos-shell rename to scripts/dos-shell index 684e64d..a0d37f4 100755 --- a/dos-shell +++ b/scripts/dos-shell @@ -11,6 +11,8 @@ C_DRIVE="/cdrive" ENV_DIR="/etc/dos_env" AUTOEXEC_TEMPLATE="${ENV_DIR}/AUTOEXEC.BAT" CONFIG_TEMPLATE="${ENV_DIR}/CONFIG.SYS" +SVARDOS_BASE="/opt/svardos/base" +ALLOW_MODE="${DOS_ALLOW_MODE:-all}" # default to exposing everything from the repo if [ "$(id -u)" -eq 0 ] && [ ! -d "${ENV_DIR}" ]; then mkdir -p "${ENV_DIR}" @@ -20,31 +22,54 @@ fi rm -rf "${C_DRIVE:?}/"* mkdir -p "${C_DRIVE}" -# Collect the list of allowed files and sync them into the C: drive -allowed_entries=() -if [ -f "${ALLOWED_LIST}" ]; then - while IFS= read -r line || [ -n "$line" ]; do - # trim whitespace - line="$(printf '%s' "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - # skip blank/comment lines - case "$line" in - ''|\#*) continue ;; - esac - allowed_entries+=("$line") - done < "${ALLOWED_LIST}" +# Seed the C: drive with the SvarDOS base image +if [ -e "${SVARDOS_BASE}/COMMAND.COM" ] || [ -e "${SVARDOS_BASE}/command.com" ]; then + cp -a "${SVARDOS_BASE}/." "${C_DRIVE}/" +else + echo "SvarDOS base not found in ${SVARDOS_BASE}. Aborting." >&2 + exit 1 fi -# Copy allowed files into the DOS C: drive -for entry in "${allowed_entries[@]}"; do - src="${ALLOWED_REPO}/${entry}" - if [ -e "$src" ]; then - dst_dir="$(dirname "${entry}")" - mkdir -p "${C_DRIVE}/${dst_dir}" - cp -a "$src" "${C_DRIVE}/${dst_dir}/" - else - echo "Warning: allowed file not found: $src" >&2 +# Sync additional DOS files into the C: drive +allowed_entries=() +case "${ALLOW_MODE}" in + all) + if [ -d "${ALLOWED_REPO}" ] && [ "$(ls -A "${ALLOWED_REPO}")" ]; then + cp -a "${ALLOWED_REPO}/." "${C_DRIVE}/" + fi + ;; + list|allowlist) + ;; + *) + echo "Unknown DOS_ALLOW_MODE '${ALLOW_MODE}', falling back to allowlist mode." >&2 + ALLOW_MODE="list" + ;; +esac + +if [ "${ALLOW_MODE}" != "all" ]; then + if [ -f "${ALLOWED_LIST}" ]; then + while IFS= read -r line || [ -n "$line" ]; do + # trim whitespace + line="$(printf '%s' "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + # skip blank/comment lines + case "$line" in + ''|\#*) continue ;; + esac + allowed_entries+=("$line") + done < "${ALLOWED_LIST}" fi -done + + for entry in "${allowed_entries[@]}"; do + src="${ALLOWED_REPO}/${entry}" + if [ -e "$src" ]; then + dst_dir="$(dirname "${entry}")" + mkdir -p "${C_DRIVE}/${dst_dir}" + cp -a "$src" "${C_DRIVE}/${dst_dir}/" + else + echo "Warning: allowed file not found: $src" >&2 + fi + done +fi # Optional: create an AUTOEXEC.BAT and CONFIG.SYS or other DOS boot files autoexec_path="${C_DRIVE}/AUTOEXEC.BAT" @@ -60,7 +85,9 @@ echo Welcome to the containerized DOS environment. EOF fi -if [ ${#allowed_entries[@]} -gt 0 ]; then +if [ "${ALLOW_MODE}" = "all" ]; then + printf 'echo All repository programs are currently enabled.\r\n' >> "${autoexec_path}" +elif [ ${#allowed_entries[@]} -gt 0 ]; then { printf 'echo Allowed programs:\r\n' for entry in "${allowed_entries[@]}"; do diff --git a/scripts/prepare-svardos.sh b/scripts/prepare-svardos.sh new file mode 100644 index 0000000..1b94b38 --- /dev/null +++ b/scripts/prepare-svardos.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -euo pipefail + +SVARDOS_BASE_DIR="/opt/svardos/base" +SVARDOS_CACHE="/opt/svardos/cache" +SVARDOS_IMG="${SVARDOS_CACHE}/svardos.img" +DEFAULT_REL="download/20250427/svardos-20250427-floppy-1.44M.zip" +DEFAULT_BASE="http://svardos.org" + +if [ -z "${SVARDOS_IMG_URL:-}" ]; then + homepage="$( + curl -fsSL "${DEFAULT_BASE}/" 2>/dev/null || true + )" + discovered_rel="" + if [ -n "$homepage" ]; then + for pattern in 'download/[0-9]+/svardos-[0-9]+-floppy-1\.44M\.zip' 'download/[0-9]+/svardos-[0-9]+-usb\.zip'; do + candidate="$(printf '%s' "$homepage" | grep -Eo "$pattern" | head -n1)" + if [ -n "$candidate" ]; then + discovered_rel="$candidate" + break + fi + done + fi + if [ -n "$discovered_rel" ]; then + SVARDOS_IMG_URL="${DEFAULT_BASE}/${discovered_rel}" + else + SVARDOS_IMG_URL="${DEFAULT_BASE}/${DEFAULT_REL}" + fi +fi + +if [ -e "${SVARDOS_BASE_DIR}/COMMAND.COM" ] || [ -e "${SVARDOS_BASE_DIR}/command.com" ]; then + exit 0 +fi + +mkdir -p "${SVARDOS_BASE_DIR}" "${SVARDOS_CACHE}" + +tmp_archive="${SVARDOS_CACHE}/svardos_download" +rm -f "${tmp_archive}" "${SVARDOS_IMG}" + +echo "Fetching SvarDOS base from ${SVARDOS_IMG_URL}" +curl -fsSL "${SVARDOS_IMG_URL}" -o "${tmp_archive}" + +mime_type="$(file -b --mime-type "${tmp_archive}")" +case "${mime_type}" in + application/zip) + unzip -o "${tmp_archive}" -d "${SVARDOS_CACHE}" >/dev/null + ;; + application/x-bzip2|application/x-gzip|application/x-xz) + tar -xf "${tmp_archive}" -C "${SVARDOS_CACHE}" + ;; + application/octet-stream) + # assume this is already a raw image + cp "${tmp_archive}" "${SVARDOS_IMG}" + ;; + *) + echo "Unsupported SvarDOS payload type: ${mime_type}" >&2 + exit 1 + ;; +esac + +if [ ! -f "${SVARDOS_IMG}" ]; then + # try to locate the image file + candidate="$(find "${SVARDOS_CACHE}" -maxdepth 1 -type f \( -iname '*svardos*.img' -o -iname '*.ima' -o -iname '*.img' \) | head -n1)" + if [ -z "${candidate}" ]; then + echo "Could not locate a SvarDOS disk image after extraction." >&2 + exit 1 + fi + mv "${candidate}" "${SVARDOS_IMG}" +fi + +rm -rf "${SVARDOS_BASE_DIR}"/* +mkdir -p "${SVARDOS_BASE_DIR}" + +# Copy contents of FAT image into the base directory +mcopy -s -i "${SVARDOS_IMG}" ::* "${SVARDOS_BASE_DIR}/" + +rm -f "${SVARDOS_IMG}" "${tmp_archive}" +rm -rf "${SVARDOS_CACHE}" +echo "SvarDOS base copied to ${SVARDOS_BASE_DIR}" diff --git a/start-services.sh b/scripts/start-services.sh similarity index 100% rename from start-services.sh rename to scripts/start-services.sh