You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
6.5 KiB
231 lines
6.5 KiB
package main
|
|
|
|
// Copyright (c) 2025 Robert Strutts <bobs@NewToFaith.com>
|
|
// License: MIT
|
|
// GIT: https://git.mysnippetsofcode.com/bobs/execguard
|
|
|
|
import (
|
|
"execguard/core/alert"
|
|
"execguard/core/configure"
|
|
"execguard/core/rotating_logger"
|
|
"execguard/core/hasher"
|
|
"execguard/core/make_key"
|
|
"execguard/core/monitor_running_bins"
|
|
"execguard/core/new_file_monitor"
|
|
"execguard/core/scanner"
|
|
"execguard/core/sys_database"
|
|
"database/sql"
|
|
"flag"
|
|
"log"
|
|
"strings"
|
|
"os"
|
|
"fmt"
|
|
"time"
|
|
"path/filepath"
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
const (
|
|
configFileDefault = "/etc/execguard/config.yaml"
|
|
dbFileDefault = "/etc/execguard/system.db"
|
|
logFileDefault = "/var/log/execguard.log"
|
|
mailPathDefault = "/usr/bin/mail"
|
|
clamscanDefault = "/usr/bin/clamscan"
|
|
scanIntervalDefault = 0 // Disabled
|
|
)
|
|
|
|
var (
|
|
downloadsDefault []string
|
|
downloads []string
|
|
configFile string
|
|
dbFile string
|
|
logFile string
|
|
mailPath string
|
|
clamscanPath string
|
|
scanIntervalFlag int
|
|
downloadsFlag string
|
|
configFlag string
|
|
dbFlag string
|
|
logFlag string
|
|
mailFlag string
|
|
clamscanFlag string
|
|
initMode bool
|
|
enforceMode bool
|
|
initFile string
|
|
updateFile string
|
|
migrateMode bool
|
|
newKey bool
|
|
dirs []string
|
|
scanInterval int
|
|
config *configure.Config
|
|
)
|
|
|
|
func main() {
|
|
var err error
|
|
|
|
flag.IntVar(&scanIntervalFlag, "scanDelayMinutes", 99, "0 disables scanner")
|
|
flag.StringVar(&downloadsFlag, "downloads", "none", "use specified Downloads folders comma-seperated list")
|
|
flag.StringVar(&configFlag, "config", "", "use specified file for config")
|
|
flag.StringVar(&dbFlag, "db", "", "use specified file for database")
|
|
flag.StringVar(&logFlag, "log", "", "use specified file for Logging")
|
|
flag.StringVar(&mailFlag, "mail", "", "use specified file for Mail sending")
|
|
flag.StringVar(&clamscanFlag, "scanner", "", "use specified binary for Virus Scanning")
|
|
flag.BoolVar(&initMode, "init", false, "initialize and populate allowed executable database")
|
|
flag.BoolVar(&enforceMode, "enforce", false, "enforce policies from Database Lock-down...")
|
|
flag.StringVar(&initFile, "initFile", "", "file containing files to add to allowed database with hash")
|
|
flag.StringVar(&updateFile, "update", "", "add specified file to allowed database with hash")
|
|
flag.BoolVar(&migrateMode, "migrate", false, "recompute hashes of all allowed paths using current settings")
|
|
flag.BoolVar(&newKey, "newKey", false, "generate a new XXTEA-compatible encryption key")
|
|
flag.Parse()
|
|
|
|
if newKey {
|
|
if make_key.Make_a_key() {
|
|
return
|
|
} else {
|
|
os.Exit(1) // Exit with status code 1
|
|
}
|
|
}
|
|
|
|
if os.Geteuid() != 0 {
|
|
fmt.Printf("This program must be run as root")
|
|
os.Exit(1) // Exit with status code 1
|
|
}
|
|
|
|
scanner.SetModes(initMode, initFile, updateFile, migrateMode)
|
|
monitor_running_bins.SetModes(initMode, initFile, updateFile, migrateMode)
|
|
sys_database.SetModes(initMode, initFile, updateFile, migrateMode)
|
|
|
|
if configFlag != "" {
|
|
configFile = configFlag
|
|
} else {
|
|
configFile = configFileDefault
|
|
}
|
|
|
|
if logFlag != "" {
|
|
logFile = logFlag
|
|
} else {
|
|
logFile = logFileDefault
|
|
}
|
|
|
|
config, err := configure.LoadConfig(configFile, logFile)
|
|
if err != nil {
|
|
fmt.Printf("Error loading config: %v", err)
|
|
os.Exit(3) // Exit with status code 3
|
|
}
|
|
|
|
hasher.SetGlobalConfig(*config)
|
|
alert.SetGlobalConfig(*config)
|
|
monitor_running_bins.SetGlobalConfig(*config)
|
|
scanner.SetGlobalConfig(*config)
|
|
|
|
// Set Vars...arguemtns first, then config, then defaults
|
|
if dbFlag != "" {
|
|
dbFile = dbFlag
|
|
} else if config.DbFile != "" {
|
|
dbFile = config.DbFile
|
|
} else {
|
|
dbFile = dbFileDefault
|
|
}
|
|
|
|
if mailFlag != "" {
|
|
mailPath = mailFlag
|
|
} else if config.MailProg != "" {
|
|
mailPath = config.MailProg
|
|
} else {
|
|
mailPath = mailPathDefault
|
|
}
|
|
|
|
alert.SetGlobalMail(mailPath)
|
|
|
|
if clamscanFlag != "" {
|
|
clamscanPath = clamscanFlag
|
|
} else if config.ScannerProg != "" {
|
|
clamscanPath = config.ScannerProg
|
|
} else {
|
|
clamscanPath = clamscanDefault
|
|
}
|
|
|
|
if scanIntervalFlag != 99 {
|
|
scanInterval = scanIntervalFlag
|
|
} else if config.ScanInterval != 99 {
|
|
scanInterval = config.ScanInterval
|
|
} else {
|
|
scanInterval = scanIntervalDefault
|
|
}
|
|
|
|
if downloadsFlag != "none" {
|
|
downloads = strings.Split(downloadsFlag, ",")
|
|
}
|
|
|
|
if len(downloads) > 0 {
|
|
dirs = downloads
|
|
} else if len(config.Downloads) > 0 {
|
|
dirs = config.Downloads
|
|
} else {
|
|
dirs = downloadsDefault
|
|
}
|
|
|
|
rl, err := rotating_logger.NewRotatingLogger(config.Logging)
|
|
if err != nil {
|
|
fmt.Printf("Failed to initialize logger: %v", err)
|
|
}
|
|
defer rl.Close()
|
|
|
|
logger := log.New(rl, "", 0)
|
|
logger.SetPrefix(fmt.Sprintf("[%s] ", time.Now().Format(config.Logging.TimestampFormat)))
|
|
|
|
db, err := sql.Open("sqlite3", dbFile)
|
|
if err != nil {
|
|
logger.Fatalf("Error opening database: %v", err)
|
|
os.Exit(2) // Exit with status code 2
|
|
}
|
|
defer db.Close()
|
|
|
|
sys_database.CreateTable(db, logger)
|
|
|
|
if initFile != "" {
|
|
absPath, err := filepath.Abs(initFile)
|
|
if err != nil {
|
|
logger.Fatalf("Invalid init file path: %v", err)
|
|
os.Exit(1) // Exit with status code 1
|
|
}
|
|
sys_database.RunInit(db, logger, absPath)
|
|
return
|
|
}
|
|
|
|
if updateFile != "" {
|
|
absPath, err := filepath.Abs(updateFile)
|
|
if err != nil {
|
|
logger.Fatalf("Invalid update file path: %v", err)
|
|
os.Exit(1) // Exit with status code 1
|
|
}
|
|
sys_database.AddToAllowed(db, logger, absPath)
|
|
logger.Printf("Added to allowed list: %s", absPath)
|
|
return
|
|
}
|
|
|
|
if migrateMode {
|
|
sys_database.RunMigration(db, logger)
|
|
return
|
|
}
|
|
|
|
if scanInterval > 0 {
|
|
go func() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
logger.Printf("Recovered from scan panic: %v", r)
|
|
}
|
|
}()
|
|
scanner.PeriodicScan(config.ProtectedDirs, db, logger, mailPath, scanInterval)
|
|
}()
|
|
}
|
|
|
|
if len(dirs) > 0 {
|
|
go new_file_monitor.Monitor_new_files(dirs, db, logger, clamscanPath)
|
|
}
|
|
|
|
if err := monitor_running_bins.MonitorExecutions(db, logger, mailPath); err != nil {
|
|
logger.Fatalf("Execution monitoring failed: %v", err)
|
|
os.Exit(4) // Exit with status code 4
|
|
}
|
|
}
|
|
|