Linux启动阶段验证授权文件:无授权则阻止启动并要求激活
完全可以实现你要的需求——在系统启动时检查授权文件,不存在则要求输入密钥,验证失败就重启系统。你之前遇到的init脚本无法输出和获取输入的问题,主要是因为早期启动阶段stdout/stdin还没默认绑定到控制台,只要明确指定控制台设备就能解决。下面分主流的systemd和传统SysVinit两种场景给你具体方案:
一、Systemd系统(绝大多数现代Linux发行版:Ubuntu、CentOS 7+、Debian 9+等)
1. 编写授权验证脚本
创建一个可执行脚本/usr/local/bin/check_license.sh,负责检查授权文件、获取用户输入并处理验证逻辑:
#!/bin/bash # 定义授权文件路径和控制台设备 LICENSE_FILE="/etc/license.key" CONSOLE="/dev/console" # 输出信息到控制台(解决早期启动无输出的问题) echo "=== System License Check ===" > $CONSOLE # 检查授权文件是否存在 if [ ! -f "$LICENSE_FILE" ]; then echo "License file not detected! Please enter your activation key:" > $CONSOLE # 从控制台读取用户输入 read -r ACTIVATION_KEY < $CONSOLE # 这里替换为你的密钥验证逻辑(示例:对比预设的有效密钥哈希或调用验证逻辑) # 建议用哈希对比,避免明文存储有效密钥,比如: # EXPECTED_HASH="5d41402abc4b2a76b9719d911017c592" # INPUT_HASH=$(echo -n "$ACTIVATION_KEY" | md5sum | cut -d' ' -f1) # if [ "$INPUT_HASH" = "$EXPECTED_HASH" ]; then if [ "$ACTIVATION_KEY" = "YOUR_VALID_ACTIVATION_KEY" ]; then echo "Activation successful! Saving license file..." > $CONSOLE echo "$ACTIVATION_KEY" > "$LICENSE_FILE" echo "Proceeding with system boot..." > $CONSOLE else echo "ERROR: Invalid activation key!" > $CONSOLE echo "System will restart in 5 seconds..." > $CONSOLE sleep 5 # 强制重启 reboot -f fi else # 可选:验证现有授权文件的有效性(避免篡改) echo "License file found, verifying validity..." > $CONSOLE EXISTING_KEY=$(cat "$LICENSE_FILE") if [ "$EXISTING_KEY" != "YOUR_VALID_ACTIVATION_KEY" ]; then echo "ERROR: Invalid existing license!" > $CONSOLE echo "Please re-enter your activation key:" > $CONSOLE read -r ACTIVATION_KEY < $CONSOLE if [ "$ACTIVATION_KEY" != "YOUR_VALID_ACTIVATION_KEY" ]; then echo "Invalid key! Restarting system..." > $CONSOLE sleep 5 reboot -f else echo "License reactivated successfully!" > $CONSOLE echo "$ACTIVATION_KEY" > "$LICENSE_FILE" fi else echo "License validation passed. Proceeding with boot..." > $CONSOLE fi fi
给脚本添加执行权限:
chmod +x /usr/local/bin/check_license.sh
2. 创建Systemd服务,让脚本在启动最早期运行
创建服务文件/etc/systemd/system/check-license.service,确保它在系统初始化前执行:
[Unit] Description=Validate System License Before Boot Before=sysinit.target DefaultDependencies=no [Service] Type=oneshot ExecStart=/usr/local/bin/check_license.sh # 绑定控制台作为输入输出设备 StandardInput=tty StandardOutput=tty StandardError=tty TTYPath=/dev/console [Install] WantedBy=sysinit.target
启用并生效服务:
systemctl daemon-reload systemctl enable check-license.service
这样系统每次启动时,都会先运行这个脚本,只有授权验证通过才会继续启动到Shell/GUI;验证失败则直接重启。
二、SysVinit系统(老版本CentOS、Debian等)
对于使用SysVinit的系统,直接修改/etc/inittab,让验证脚本在系统初始化的最开始运行:
打开/etc/inittab,在最顶部添加一行:
si::sysinit:/usr/local/bin/check_license.sh
保存后,下次启动就会先执行验证脚本。脚本的内容和systemd版本一致,同样通过/dev/console处理输入输出。
关键问题解决:为什么你的init脚本无法输出/获取输入?
早期启动阶段,系统还没完成控制台的初始化绑定,stdout/stdin并没有默认关联到物理控制台。所以在脚本里明确把输出重定向到/dev/console,并从/dev/console读取输入,就能解决这个问题。在systemd服务里通过StandardInput=tty和TTYPath=/dev/console配置,也是同样的道理——强制把脚本的IO绑定到控制台设备。
内容的提问来源于stack exchange,提问作者Malik Hamza Murtaza

