Files
rust_raidguardx/GC_PasswordSystem.md
T
2026-03-29 00:54:38 +08:00

6.1 KiB

密碼系統分析

概述

RAIDGuard X 使用密碼系統來控制對 RAID 控制器的訪問權限。以下是密碼相關的功能:

密碼類型

密碼類型 說明 預設值
控制器密碼 連線到控制器時驗證 00000000
進階功能密碼 用於進階功能 (如 Update Firmware) WANGWANG=AU4@A83

密碼驗證流程

1. 密碼檢查 (PwdCheck)

使用者操作進階功能
  → PwdCheck(loc)
  → 檢查 sPwd[SN] 是否為空
  → 若為空,彈出密碼輸入對話框 (dlgPasswordCheck)
  → 驗證密碼正確性
  → 成功後才允許執行

2. 密碼輸入對話框 (dlgPasswordCheck)

// dlgPasswordCheck.java
public void jbOk_actionPerformed() {
    // 取得使用者輸入的密碼 (8 字元)
    String inputPwd = jpPwd.getSelectedText();
    
    // 儲存到 PageDataDB.sPwd[]
    PageDataDB.sPwd[SNToNo(sSN)] = inputPwd + "        ";
    
    // 發送密碼到控制器驗證
    // OpCode: 0x1D
    // SubOp: 0x08
    // 密碼: raw char values (無轉換)
    bCmds[3] = 0x1D;  // OpCode
    bCmds[4] = 0x08;  // Length
    bCmds[5-12] = password bytes (charAt(i))
}

密碼發送機制

OpCode: 0x1D - SEND_PASSWORD

CDB 結構:

Offset 說明
0 0x00 Phase Code
1 0x00 Request Code
2 0x00 Controller No
3 0x1D OpCode - SEND_PASSWORD
4 0x08 Length (8 bytes)
5-12 password 8 bytes password

密碼位元組轉換

有兩種不同的轉換方式:

方式 1: dlgPasswordCheck (直接發送)

// 密碼直接作為 char 發送
bCmds[5] = (byte) password.charAt(0);
bCmds[6] = (byte) password.charAt(1);
// ...

方式 2: SendCmd.sendPassword (減法轉換)

// 密碼字元減去 0x30
pwdBytes[i] = (byte) (password.charAt(i) - 0x30);

// Example:
// '0' (0x30) → 0x00
// '1' (0x31) → 0x01
// '9' (0x39) → 0x09
// 'A' (0x41) → 0x11

密碼儲存

PageDataDB.sPwd[]

// 全域密碼儲存陣列
public static String sPwd[] = new String[iMaxHosts];

// 根據序號查詢密碼索引
public static int SNToNo(String sSN) {
    // 查詢 sSNToNo[][] 對應表
    // 回傳該 SN 的密碼陣列索引
}

// 儲存密碼
PageDataDB.sPwd[SNToNo(sSN)] = "00000000";

密碼對應表

sSNToNo[i][0] = 控制器序號 (String)
sSNToNo[i][1] = 密碼索引 (String "0"-"15")

預設密碼

預設控制器密碼

預設值: "00000000" (8 個零)

進階功能密碼

PageDataDB.GetPlayMenu() 中檢查:

if (sPwd[SNToNo(sSN)].trim().equals("=AU4@A83") ||
    sPwd[SNToNo(sSN)].trim().equals("WANGWANG")) {
    // 啟用進階功能 (Play Menu)
}
密碼 用途
00000000 預設控制器連線密碼
WANGWANG 啟用 Play Menu 進階功能
=AU4@A83 啟用 Play Menu 進階功能 (另一組)

需要密碼的功能

以下功能需要密碼驗證:

功能 密碼類型
Update System Code (Firmware) 控制器密碼
Update Boot Code 控制器密碼
Update BIOS/EFI 控制器密碼
Update Expander Code 控制器密碼
Dump Controller Log 控制器密碼
Shutdown Controller 控制器密碼
Play Menu 進階密碼 (WANGWANG=AU4@A83)

密碼對話框

dlgPasswordCheck

┌────────────────────────────────────────┐
│  Password Check                        │
│                                        │
│  [________________]                   │
│  (Default Password: 00000000)         │
│                                        │
│         [OK]    [Cancel]              │
└────────────────────────────────────────┘

密碼欄位設定

// 固定長度 8 字元
jpPwd.setDocument(new FixedSizePlainDocument(8));
jpPwd.setSelectionEnd(8);

// 密碼可視 (不遮蔽)
// jpPwd.setEchoChar('*');

Code Flow

密碼驗證流程

1. 使用者點擊功能 (如 Update Firmware)
2. frmMain.jmXXX_actionPerformed()
3. PageDataDB.PwdCheck(loc)
4. 
   a. 若 sPwd[SN] 已有密碼 → 自動使用
   b. 若 sPwd[SN] 為空 → 彈出 dlgPasswordCheck
5. 
   a. 驗證成功 → bPwdCheckPass = true → 執行功能
   b. 驗證失敗 → bPwdCheckPass = false → 拒絕執行

密碼發送流程

1. dlgPasswordCheck.jbOk_actionPerformed()
2. 取得輸入密碼 → 儲存到 sPwd[SN]
3. 建立 CmdQueue 命令
4. 
   a. dlgPasswordCheck: 使用 raw char (無轉換)
   b. SendCmd.sendPassword: 使用 char - 0x30 轉換
5. 發送到控制器 (OpCode 0x1D)
6. 等待回應
7. 驗證成功 → 刷新頁面資料

關鍵類

類別 檔案 功能
PageDataDB PageDataDB.java 密碼儲存與驗證
dlgPasswordCheck dlgPasswordCheck.java 密碼輸入對話框
SendCmd InBandAPI/SendCmd.java 密碼發送通訊

參考程式碼

SendCmd.sendPassword()

public void sendPassword(String sIP, String sSN) {
    // 取得密碼
    String rawPwdStr = PageDataDB.sPwd[SNToNo(sSN)];
    
    // 密碼轉換: char - 0x30
    byte[] pwdBytes = new byte[8];
    for (int i = 0; i < 8; i++) {
        pwdBytes[i] = (byte) (rawPwdStr.charAt(i) - 0x30);
    }
    
    // 發送
    // OpCode: 0x1D
    // Length: 0x08
    // Data: pwdBytes[0..7]
    this.send(sIP, sSN, (byte) 0x1D, (byte) 0x08,
        pwdBytes[0], pwdBytes[1], pwdBytes[2], pwdBytes[3],
        pwdBytes[4], pwdBytes[5], pwdBytes[6], pwdBytes[7]);
}

PageDataDB.PwdCheck()

public static int PwdCheck(Point loc) {
    if (sSN.trim().equals("")) {
        return 0x00;  // 無控制器
    }
    
    if (sPwd[SNToNo(sSN)].equals("")) {
        // 彈出密碼輸入對話框
        dlgPasswordCheck dlgPwdCheck = new dlgPasswordCheck();
        dlgPwdCheck.setVisible(true);
        
        if (dlgPwdCheck.bPwdCheckPass == false) {
            return 0x00;  // 驗證失敗
        }
    }
    
    return 0x01;  // 驗證成功
}