176 lines
4.1 KiB
Go
176 lines
4.1 KiB
Go
package whitelist
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/wuko233/sysmonitord/internal/config"
|
|
)
|
|
|
|
type FileStatus string
|
|
|
|
const (
|
|
StatusIgnored FileStatus = "IGNORED"
|
|
StatusNonWhitelisted FileStatus = "NON_WHITELISTED"
|
|
StatusHashMismatch FileStatus = "HASH_MISMATCH"
|
|
StatusSafe FileStatus = "SAFE"
|
|
)
|
|
|
|
type Manager struct {
|
|
mu sync.RWMutex
|
|
official config.OfficialConfig
|
|
user config.UserConfig
|
|
mergedIgnore []string
|
|
}
|
|
|
|
func NewManager(o config.OfficialConfig, u config.UserConfig) *Manager {
|
|
m := &Manager{
|
|
official: o,
|
|
user: u,
|
|
}
|
|
|
|
m.mergedIgnore = append([]string{}, m.official.IgnoredPaths...)
|
|
m.mergedIgnore = append(m.mergedIgnore, m.user.IgnoredPaths...)
|
|
|
|
return m
|
|
}
|
|
|
|
func (m *Manager) UpdateConfig(official config.OfficialConfig, user config.UserConfig) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
m.official = official
|
|
m.user = user
|
|
|
|
m.mergedIgnore = append([]string{}, m.official.IgnoredPaths...)
|
|
m.mergedIgnore = append(m.mergedIgnore, m.user.IgnoredPaths...)
|
|
}
|
|
|
|
func (m *Manager) IsPathIgnored(path string) bool {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
return m.IsPathIgnoredUnsafe(path)
|
|
}
|
|
|
|
func (m *Manager) IsPathIgnoredUnsafe(path string) bool {
|
|
path = filepath.Clean(path)
|
|
for _, ignore := range m.mergedIgnore {
|
|
if strings.HasPrefix(path, filepath.Clean(ignore)) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// CheckFileStatus 检查文件状态
|
|
// 返回: isWhitelisted(是否在白名单), isValid(Hash是否匹配), err
|
|
func (m *Manager) CheckFileStatus(path string) (bool, bool, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
// 1. 首先检查是否在忽略列表中
|
|
if m.IsPathIgnoredUnsafe(path) {
|
|
return true, true, nil
|
|
}
|
|
|
|
// 2. 合并官方和用户的白名单(并集策略)
|
|
var allowedHashes []string
|
|
|
|
// 添加官方白名单 Hash
|
|
if officialHashes, exists := m.official.WhitelistFiles[path]; exists {
|
|
allowedHashes = append(allowedHashes, officialHashes...)
|
|
}
|
|
|
|
// 添加用户补充白名单 Hash
|
|
if userHashes, exists := m.user.SupplementFiles[path]; exists {
|
|
allowedHashes = append(allowedHashes, userHashes...)
|
|
}
|
|
|
|
// 如果两个白名单都没有这个文件
|
|
if len(allowedHashes) == 0 {
|
|
return false, false, nil
|
|
}
|
|
|
|
// 3. 计算当前文件 Hash
|
|
fileHash, err := CalculateFileHash(path)
|
|
if err != nil {
|
|
return true, false, fmt.Errorf("计算文件哈希失败: %v", err)
|
|
}
|
|
|
|
// 4. 检查 Hash 是否在允许列表中
|
|
for _, h := range allowedHashes {
|
|
// 支持 sha256:xxx 格式或纯 hash 格式
|
|
normalizedHash := h
|
|
if strings.HasPrefix(h, "sha256:") {
|
|
normalizedHash = h[7:]
|
|
}
|
|
if strings.EqualFold(normalizedHash, fileHash) {
|
|
return true, true, nil
|
|
}
|
|
}
|
|
|
|
// 在白名单中但 Hash 不匹配
|
|
return true, false, nil
|
|
}
|
|
|
|
func CalculateFileHash(filePath string) (string, error) {
|
|
file, err := os.Open(filePath)
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
hash := sha256.New()
|
|
if _, err := io.Copy(hash, file); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return hex.EncodeToString(hash.Sum(nil)), nil
|
|
}
|
|
|
|
func (m *Manager) IsProcessAllowed(procName string, cmdLine string) bool {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
// 检查官方白名单
|
|
for _, p := range m.official.WhitelistProcesses {
|
|
if p == procName {
|
|
return true
|
|
}
|
|
}
|
|
|
|
// 检查用户补充白名单(数组形式)
|
|
for _, p := range m.user.SupplementProcesses {
|
|
if p == procName {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (m *Manager) GetAuditServerUrl() string {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
return m.user.Connection.AuditServerURL
|
|
}
|
|
|
|
func (m *Manager) rebuildIgnoreList() {
|
|
totalLen := len(m.official.IgnoredPaths) + len(m.user.IgnoredPaths)
|
|
|
|
// 预分配容量以提高性能
|
|
m.mergedIgnore = make([]string, 0, totalLen)
|
|
m.mergedIgnore = append(m.mergedIgnore, m.official.IgnoredPaths...)
|
|
m.mergedIgnore = append(m.mergedIgnore, m.user.IgnoredPaths...)
|
|
}
|