Files
STM32F4-Base/Drivers/BSP/NET/lftpd/lftpd_auth.c
T
wandering1 d1e6bb4ba7 W5波+N-19收口:FTP鉴权落地、Trap25三连定案修复(N-30)、N-20/N-23/N-26
N-19 FTP 鉴权:
- lftpd_auth(USER/PASS 状态机 + 连续5次失败锁60s)+ SHA-256
  (user||pwd) 口令哈希;config.ini [ftp] 段 user/pwd_hash/write,
  出厂 admin/admin 在用有启动告警;lftpd_log.c 删除并入 lftpd_auth
- ftp_cfg 配置读写;台架 ftp_auth_bench.py 13/13

N-30 / Trap 25(CH395F_Trap_Records.md 四次定案全记录):
- 修复1 closed-with-data accept:客户端发完正常 FIN 后芯片按
  FUN_PARA(0x09) §5.52② 保留 Socket+RX 缓冲,旧代码把 CLOSED 一律
  relisten 自毁缓冲 → STOR 必挂 425;改为接受"已关但可读"连接排空
- 修复2 丢 CONNECT 中断探针 net_lost_connect_probe + last_peer_port
  幽灵甄别(拆链窗口握手完成但中断丢失,双信源去抖补 accept)
- 修复3 send_list/send_nlst 批量单发:背靠背 ~60B 小段毒化芯片 TX
  (芯片报 SEND_OK 但对端全丢),整份目录一次性写入
- 证伪存档:固定沉降/Socket 轮换冷却/listen 门控(台架 v7 矩阵)
- 台架工具 test/board/ch395f_reuse_bench.{c,h} + host 脚本存档
  (不注册编译;实验分支 n30-chip-bench 保留)

N-20:Error_Handler 死循环降级(记录+复位路径)
N-23:scripts/check_registration.py 双端注册反向校验(pre-commit)
N-26:GD5F NAND 直 DMA 调用方缓冲窗口断言

验证:BUILD_OK 0/0;ftp_regression 连跑 4 轮 11/11(修复前
LIST#4/#7 100% 挂、STOR#2 曾 100% 425);ftp_auth_bench 13/13;
@test 启动标记 PASS;ci_local L0+L0.5 全过;doc-links 通过。
登记簿 N-30 已销项。
2026-10-11 18:50:24 +08:00

101 lines
3.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称:lftpd_auth
* 模块功能:FTP 鉴权状态机实现(纯函数,仅依赖 stdint/string 与 sha256)
* 适用平台:STM32F407ZGTx / PC 主机侧单测(双端共用)
* 作者:王建锋
* 创建日期:2026-10-11
* 修改记录:
* v1.0 2026-10-11 王建锋 创建初始版本(N-19 FTP 鉴权;契约由
* test/host/ftp_auth 主机单测钉死)
*/
/* 头文件包含区 */
#include <stddef.h>
#include <string.h>
#include "lftpd_auth.h"
#include "sha256.h"
/* 函数定义区 */
/*
* 函数功能:用户名匹配(大小写不敏感)
* 入口参数:p_expect - 配置用户名 p_user - 客户端 USER 参数
* 返回值:1 - 匹配;0 - 不匹配或任一为 NULL int
* 限定条件:无
*/
int ftp_auth_user_match(const char *p_expect, const char *p_user) {
if ((p_expect == NULL) || (p_user == NULL)) {
return 0;
}
for (size_t i = 0u; ; i++) {
char a = p_expect[i];
char b = p_user[i];
if ((a >= 'A') && (a <= 'Z')) {
a = (char)(a + 32);
}
if ((b >= 'A') && (b <= 'Z')) {
b = (char)(b + 32);
}
if (a != b) {
return 0;
}
if (a == '\0') {
return 1;
}
}
}
/*
* 函数功能:口令校验 + 失败计数 + 限时锁定(鉴权契约核心)
* 入口参数:p_creds - 凭据 user_ok - USER 阶段匹配结果 p_pass - 口令
* p_state - 会话外共享状态 now_tick - 当前 tick(ms)
* 返回值:FTP_AUTH_OK / FAIL / LOCKED(枚举)
* 限定条件:锁定判定先于哈希(锁定期内不做哈希);用户名错也走哈希(耗时拉平);
* tick 有符号差抗 32 位回绕;NULL 入参 fail-closed 返回 FAIL
*/
ftp_auth_result_t ftp_auth_check(const ftp_auth_creds_t *p_creds,
uint8_t user_ok, const char *p_pass,
ftp_auth_state_t *p_state, uint32_t now_tick) {
sha256_ctx_t ctx;
uint8_t digest[SHA256_DIGEST_SIZE];
int ok;
if ((p_creds == NULL) || (p_state == NULL)) {
return FTP_AUTH_FAIL; /* fail-closed */
}
if (p_state->fail_count >= FTP_AUTH_FAIL_MAX) {
/* 有符号差:now 在 lock_until 之前(含回绕)= 仍在锁定窗内 */
if ((int32_t)(now_tick - p_state->lock_until_tick) < 0) {
return FTP_AUTH_LOCKED;
}
p_state->fail_count = 0u; /* 锁定期满,重新起算 */
}
/* 盐 = 期望用户名;用户名错也走同一哈希路径(耗时拉平,见头文件说明 2) */
sha256_init(&ctx);
if (p_creds->p_user != NULL) {
sha256_update(&ctx, p_creds->p_user, strlen(p_creds->p_user));
}
if (p_pass != NULL) {
sha256_update(&ctx, p_pass, strlen(p_pass));
}
sha256_final(&ctx, digest);
ok = ((user_ok != 0u) &&
(sha256_hex_eq(digest, p_creds->p_pwd_hash) != 0)) ? 1 : 0;
if (ok != 0) {
p_state->fail_count = 0u;
return FTP_AUTH_OK;
}
p_state->fail_count++;
if (p_state->fail_count >= FTP_AUTH_FAIL_MAX) {
p_state->lock_until_tick = now_tick + FTP_AUTH_LOCK_TICKS;
}
return FTP_AUTH_FAIL;
}