/* lock_screen.h — MeowOS 锁屏 4 位 PIN(系统级安全,纯逻辑;宿主可单测)。 * * 模型(用户定案,2026-09-02): * - 设置键 `system.pin`:4 位数字 PIN 的 sha256+salt 哈希,存 settings.conf。 * 格式与面板 panel.pin **全等**:`:`,salt 16B * /dev/urandom → 32 hex;绝不存明文、绝不在日志/响应中输出 hash。 * - 面板同源迁移:`panel.pin` 已设而 `system.pin` 未设时,锁屏接受 panel.pin,并在 * **首次验证成功后并入 system.pin**(lck_pin_success 把 panel.pin 值拷入 system.pin)。 * - 锁屏时机:息屏唤醒后(默认开,`system.pin_lock_on_wake=1` 可关)+ 电源菜单「锁定」 * 手动锁;**开机不锁**(boot 进主屏不拦,本逻辑不被 boot 路径调用)。 * - 错 5 次锁 5 分钟:`system.pin_fails`(连续错计数)与 `system.pin_lock_until`(锁定 * 截止 epoch 秒)**持久化到 settings.conf**——launcher 重启不清零(面板的进程内存方案 * 在重启后失效,这里要落盘)。 * - 兜底:SSH root 删 `system.pin` 键即解锁(无其它后门)。 * * 本头只声明纯逻辑接口;渲染/输入循环在 lock_screen_ui.c(run_lock_screen)。逻辑依赖 * meow_settings_* API(与 meowpanel 的 settings_get_value 语义同源,走同一 settings.conf)。 * 宿主测试:#include "lock_screen.c" + 真实 meow_settings.c(-DMEOW_SETTINGS_FILE 覆盖)。 */ #ifndef MEOW_LOCK_SCREEN_H #define MEOW_LOCK_SCREEN_H #ifdef __cplusplus extern "C" { #endif #include #define LCK_PIN_LEN 4 /* 恰好 4 位数字 */ #define LCK_PIN_MAX_FAILS 5 /* 连续错 PIN 锁定阈值 */ #define LCK_PIN_LOCK_SEC 300 /* 锁定 5 分钟 */ #define LCK_HASH_LEN 64 /* sha256 hex 长度 */ /* ---- 设置键(必须已在 meow_settings.c g_defs 注册)---- */ #define LCK_KEY_PIN "system.pin" #define LCK_KEY_WAKE "system.pin_lock_on_wake" #define LCK_KEY_LOCK_UNTIL "system.pin_lock_until" #define LCK_KEY_FAILS "system.pin_fails" #define LCK_KEY_PANEL_PIN "panel.pin" /* 面板 PIN(read-only 兼容源) */ /* ---- 文件标志(tmpfs,重启自然消失)---- */ #define LCK_UNLOCK_ONCE_FILE "/tmp/meow_pin_unlock_once" /* 面板一次性解锁恢复口:存在即消费放行 */ #define LCK_MANUAL_LOCK_FILE "/tmp/meow_pin_locked" /* 电源菜单「锁定」主动锁标志:唤醒必锁屏 */ /* PIN 合法:恰好 4 位数字(0-9)。NULL/长度不符/含非数字 → 0。 */ int lck_pin_valid(const char *pin); /* 是否已配锁屏凭据:system.pin 设 或 panel.pin 设(锁屏可开)。 */ int lck_pin_configured(void); /* 唤醒是否应锁屏:system.pin_lock_on_wake(默认 1) 且 已配凭据。 * 仅由「息屏唤醒」路径调用——boot 路径不调,天然开机不锁。 * allow_disable=0 时忽略 WAKE 键(电源菜单「锁定」手动锁用,锁前需已配凭据)。 */ int lck_lock_required(int allow_disable); /* 明文校验:system.pin 优先;未设时回退校验 panel.pin(迁移)。恒定比较,不反解。 */ int lck_pin_check(const char *pin); /* 设置/修改 system.pin(明文→sha256+salt 落盘):校验 4 位数字;清连续错计数+锁定戳;**落盘**。 * 返回 MEOW_OK / 负错误。设置页/CLI 设锁屏 PIN 走此。 */ int lck_pin_set(const char *pin); /* 清除 system.pin(解锁兜底,SSH root 删键即解锁的同义 API):清计数+锁定戳,**落盘**。 */ int lck_pin_clear(void); /* 记录一次成功验证:首次成功时把 panel.pin 并入 system.pin(迁移);清连续错计数 + 清 * 锁定戳;**落盘**。返回 MEOW_OK。 */ int lck_pin_success(void); /* 记录一次失败:递增连续错计数(持久化);达 LCK_PIN_MAX_FAILS → 设锁定戳(now+300s)并清 * 计数。已处于锁定(now<截止)时不递增。返回**剩余锁定秒**(0=未锁)。 * 调用方须先 lck_lock_remaining() 确认未锁才让输入;已锁时本函数不改变截止。 */ int lck_pin_fail(void); /* 剩余锁定秒(0=未锁定)。若截止已过,自动清锁定戳+计数并落盘(进程内已解禁)。 */ time_t lck_lock_remaining(void); /* ---- 面板一次性解锁恢复口(tmpfs 标志文件)---- * 锁屏页进入时 / 每次重试前调用:LCK_UNLOCK_ONCE_FILE 存在 → **删除并返回 1(放行进入系统一次)**; * 不存在 → 0。不校验 PIN、不清除 system.pin 本身、不重置失败计数(重启标志自然消失)。 */ int lck_unlock_once_consume(void); /* ---- 电源菜单「锁定」主动锁标志(tmpfs,重启消失)---- * 主动锁屏:写 LCK_MANUAL_LOCK_FILE → 之后唤醒 `lck_wake_should_lock()` 无论 system.pin_lock_on_wake * 是否开都必走锁屏;解锁(PIN 或面板绕过)时清除。 */ int lck_manual_lock_set(void); /* 写标志;返回 MEOW_OK */ void lck_manual_lock_clear(void); /* 删标志(幂等) */ /* 唤醒是否应锁屏:已配凭据 且 (system.pin_lock_on_wake=1 或 主动锁标志存在)。 * 取代 lck_lock_required(1) 作为唤醒门——主动锁强制锁屏,覆盖「关闭唤醒锁」的手动锁场景。 */ int lck_wake_should_lock(void); /* ── 锁屏叠加期 App 存活探针(§310 残影修复,纯判定,宿主可单测;header-only inline)---- * 锁屏运行在 App 前台叠加会话中(overlay_pid>0,run_app_lock_overlay 置位)且该进程已成僵尸 * (调用方 proc_is_zombie 判定后传入 proc_zombie=1)→ 应中止锁屏走统一退出(返回 1)。 * 菜单直接锁屏(overlay_pid=0,无 App 可死)恒 0;此谓词不实际读 /proc。 */ static inline int lck_overlay_should_abort(int overlay_pid, int proc_zombie) { return (overlay_pid > 0 && proc_zombie) ? 1 : 0; } /* run_lock_screen() 返回值:1=已解锁,0=锁屏期间电源键息屏。叠加期 App 崩溃时返回 * LCK_OVERLAY_RET_DIED(-1)——调用方 run_app_lock_overlay 据此外走「统一退出路径」 * (不再 SIGCONT 死进程/不恢复死帧,交回 waitpid 循环回收,run_menu 重绘主屏)。 */ #define LCK_OVERLAY_RET_DIED (-1) #ifdef __cplusplus } #endif #endif /* MEOW_LOCK_SCREEN_H */