diff --git a/config/vulnDictConf.go b/config/vulnDictConf.go index 2f427e7b..1af0a943 100644 --- a/config/vulnDictConf.go +++ b/config/vulnDictConf.go @@ -14,9 +14,14 @@ import ( // VulnDictInterface is an interface of vulnsrc type VulnDictInterface interface { - CheckHTTPHealth() error Init() Validate() error + IsFetchViaHTTP() bool + CheckHTTPHealth() error + GetName() string + GetType() string + GetURL() string + GetSQLite3Path() string } // VulnDict is a base struct of vuln dicts @@ -33,6 +38,26 @@ type VulnDict struct { SQLite3Path string `json:"-"` } +// GetType returns type +func (cnf *VulnDict) GetType() string { + return cnf.Type +} + +// GetName returns name +func (cnf *VulnDict) GetName() string { + return cnf.Name +} + +// GetURL returns url +func (cnf *VulnDict) GetURL() string { + return cnf.URL +} + +// GetSQLite3Path return the path of SQLite3 +func (cnf *VulnDict) GetSQLite3Path() string { + return cnf.SQLite3Path +} + // Validate settings func (cnf *VulnDict) Validate() error { logging.Log.Infof("%s.type=%s, %s.url=%s, %s.SQLite3Path=%s", @@ -48,6 +73,9 @@ func (cnf *VulnDict) Validate() error { return xerrors.Errorf("SQLite3 path must be a *Absolute* file path. %s.SQLite3Path: %s", cnf.Name, cnf.SQLite3Path) } + if _, err := os.Stat(cnf.SQLite3Path); os.IsNotExist(err) { + logging.Log.Warnf("%s.SQLite3Path=%s file not found", cnf.Name, cnf.SQLite3Path) + } case "mysql": if cnf.URL == "" { return xerrors.Errorf(`MySQL connection string is needed. %s.url="user:pass@tcp(localhost:3306)/dbname"`, cnf.Name) @@ -70,6 +98,9 @@ func (cnf *VulnDict) Validate() error { return nil } +// Init the struct +func (cnf *VulnDict) Init() {} + func (cnf *VulnDict) setDefault(sqlite3Name string) { if cnf.Type == "" { cnf.Type = "sqlite3" diff --git a/detector/db_client.go b/detector/db_client.go index 583b6fb1..6ed8ab25 100644 --- a/detector/db_client.go +++ b/detector/db_client.go @@ -3,10 +3,7 @@ package detector import ( - "os" - "github.com/future-architect/vuls/config" - "github.com/future-architect/vuls/logging" gostdb "github.com/knqyf263/gost/db" cvedb "github.com/kotakanbe/go-cve-dictionary/db" ovaldb "github.com/kotakanbe/goval-dictionary/db" @@ -24,60 +21,50 @@ type DBClient struct { MetasploitDB metasploitdb.DB } -// DBClientConf has a configuration of Vulnerability DBs -type DBClientConf struct { - CveDictCnf config.GoCveDictConf - OvalDictCnf config.GovalDictConf - GostCnf config.GostConf - ExploitCnf config.ExploitConf - MetasploitCnf config.MetasploitConf - DebugSQL bool -} - // NewDBClient returns db clients -func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error) { - cveDriver, locked, err := NewCveDB(cnf) - if locked { - return nil, true, xerrors.Errorf("CveDB is locked: %s", - cnf.OvalDictCnf.SQLite3Path) - } else if err != nil { - return nil, locked, err +func NewDBClient(cveDict, ovalDict, gost, exploit, metasploit config.VulnDictInterface, debugSQL bool) (dbclient *DBClient, err error) { + for _, cnf := range []config.VulnDictInterface{cveDict, ovalDict, gost, exploit, metasploit} { + if err := cnf.Validate(); err != nil { + return nil, xerrors.Errorf("Failed to validate %s: %+v", cnf.GetName(), err) + } + if err := cnf.CheckHTTPHealth(); err != nil { + return nil, xerrors.Errorf("Run %s as server mode before reporting: %+v", cnf.GetName(), err) + } } - ovaldb, locked, err := NewOvalDB(cnf) + cveDriver, locked, err := NewCveDB(cveDict, debugSQL) if locked { - return nil, true, xerrors.Errorf("OvalDB is locked: %s", - cnf.OvalDictCnf.SQLite3Path) + return nil, xerrors.Errorf("SQLite3 is locked: %s", cveDict.GetSQLite3Path()) } else if err != nil { - logging.Log.Warnf("Unable to use OvalDB: %s, err: %+v", - cnf.OvalDictCnf.SQLite3Path, err) + return nil, err } - gostdb, locked, err := NewGostDB(cnf) + ovaldb, locked, err := NewOvalDB(ovalDict, debugSQL) if locked { - return nil, true, xerrors.Errorf("gostDB is locked: %s", - cnf.GostCnf.SQLite3Path) + return nil, xerrors.Errorf("SQLite3 is locked: %s", ovalDict.GetSQLite3Path()) } else if err != nil { - logging.Log.Warnf("Unable to use gostDB: %s, err: %+v", - cnf.GostCnf.SQLite3Path, err) + return nil, err } - exploitdb, locked, err := NewExploitDB(cnf) + gostdb, locked, err := NewGostDB(gost, debugSQL) if locked { - return nil, true, xerrors.Errorf("exploitDB is locked: %s", - cnf.ExploitCnf.SQLite3Path) + return nil, xerrors.Errorf("SQLite3 is locked: %s", gost.GetSQLite3Path()) } else if err != nil { - logging.Log.Warnf("Unable to use exploitDB: %s, err: %+v", - cnf.ExploitCnf.SQLite3Path, err) + return nil, err } - metasploitdb, locked, err := NewMetasploitDB(cnf) + exploitdb, locked, err := NewExploitDB(exploit, debugSQL) if locked { - return nil, true, xerrors.Errorf("metasploitDB is locked: %s", - cnf.MetasploitCnf.SQLite3Path) + return nil, xerrors.Errorf("SQLite3 is locked: %s", exploit.GetSQLite3Path()) } else if err != nil { - logging.Log.Warnf("Unable to use metasploitDB: %s, err: %+v", - cnf.MetasploitCnf.SQLite3Path, err) + return nil, err + } + + metasploitdb, locked, err := NewMetasploitDB(metasploit, debugSQL) + if locked { + return nil, xerrors.Errorf("SQLite3 is locked: %s", metasploit.GetSQLite3Path()) + } else if err != nil { + return nil, err } return &DBClient{ @@ -86,26 +73,19 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error) GostDB: gostdb, ExploitDB: exploitdb, MetasploitDB: metasploitdb, - }, false, nil + }, nil } // NewCveDB returns cve db client -func NewCveDB(cnf DBClientConf) (driver cvedb.DB, locked bool, err error) { - if cnf.CveDictCnf.IsFetchViaHTTP() { +func NewCveDB(cnf config.VulnDictInterface, debugSQL bool) (driver cvedb.DB, locked bool, err error) { + if cnf.IsFetchViaHTTP() { return nil, false, nil } - logging.Log.Debugf("open cve-dictionary db (%s)", cnf.CveDictCnf.Type) - path := cnf.CveDictCnf.URL - if cnf.CveDictCnf.Type == "sqlite3" { - path = cnf.CveDictCnf.SQLite3Path - if _, err := os.Stat(path); os.IsNotExist(err) { - logging.Log.Warnf("--cvedb-path=%s file not found. [CPE-scan](https://vuls.io/docs/en/usage-scan-non-os-packages.html#cpe-scan) needs cve-dictionary. if you specify cpe in config.toml, fetch cve-dictionary before reporting. For details, see `https://github.com/kotakanbe/go-cve-dictionary#deploy-go-cve-dictionary`", path) - return nil, false, nil - } + path := cnf.GetURL() + if cnf.GetType() == "sqlite3" { + path = cnf.GetSQLite3Path() } - - logging.Log.Debugf("Open cve-dictionary db (%s): %s", cnf.CveDictCnf.Type, path) - driver, locked, err = cvedb.NewDB(cnf.CveDictCnf.Type, path, cnf.DebugSQL) + driver, locked, err = cvedb.NewDB(cnf.GetType(), path, debugSQL) if err != nil { err = xerrors.Errorf("Failed to init CVE DB. err: %w, path: %s", err, path) return nil, locked, err @@ -114,22 +94,15 @@ func NewCveDB(cnf DBClientConf) (driver cvedb.DB, locked bool, err error) { } // NewOvalDB returns oval db client -func NewOvalDB(cnf DBClientConf) (driver ovaldb.DB, locked bool, err error) { - if cnf.OvalDictCnf.IsFetchViaHTTP() { +func NewOvalDB(cnf config.VulnDictInterface, debugSQL bool) (driver ovaldb.DB, locked bool, err error) { + if cnf.IsFetchViaHTTP() { return nil, false, nil } - path := cnf.OvalDictCnf.URL - if cnf.OvalDictCnf.Type == "sqlite3" { - path = cnf.OvalDictCnf.SQLite3Path - - if _, err := os.Stat(path); os.IsNotExist(err) { - logging.Log.Warnf("--ovaldb-path=%s file not found", path) - return nil, false, nil - } + path := cnf.GetURL() + if cnf.GetType() == "sqlite3" { + path = cnf.GetSQLite3Path() } - - logging.Log.Debugf("Open oval-dictionary db (%s): %s", cnf.OvalDictCnf.Type, path) - driver, locked, err = ovaldb.NewDB("", cnf.OvalDictCnf.Type, path, cnf.DebugSQL) + driver, locked, err = ovaldb.NewDB("", cnf.GetType(), path, debugSQL) if err != nil { err = xerrors.Errorf("Failed to new OVAL DB. err: %w", err) if locked { @@ -141,22 +114,15 @@ func NewOvalDB(cnf DBClientConf) (driver ovaldb.DB, locked bool, err error) { } // NewGostDB returns db client for Gost -func NewGostDB(cnf DBClientConf) (driver gostdb.DB, locked bool, err error) { - if cnf.GostCnf.IsFetchViaHTTP() { +func NewGostDB(cnf config.VulnDictInterface, debugSQL bool) (driver gostdb.DB, locked bool, err error) { + if cnf.IsFetchViaHTTP() { return nil, false, nil } - path := cnf.GostCnf.URL - if cnf.GostCnf.Type == "sqlite3" { - path = cnf.GostCnf.SQLite3Path - - if _, err := os.Stat(path); os.IsNotExist(err) { - logging.Log.Warnf("--gostdb-path=%s file not found. Vuls can detect `patch-not-released-CVE-ID` using gost if the scan target server is Debian, RHEL or CentOS, For details, see `https://github.com/knqyf263/gost#fetch-redhat`", path) - return nil, false, nil - } + path := cnf.GetURL() + if cnf.GetType() == "sqlite3" { + path = cnf.GetSQLite3Path() } - - logging.Log.Debugf("Open gost db (%s): %s", cnf.GostCnf.Type, path) - if driver, locked, err = gostdb.NewDB(cnf.GostCnf.Type, path, cnf.DebugSQL); err != nil { + if driver, locked, err = gostdb.NewDB(cnf.GetType(), path, debugSQL); err != nil { if locked { return nil, true, xerrors.Errorf("gostDB is locked. err: %w", err) } @@ -166,22 +132,15 @@ func NewGostDB(cnf DBClientConf) (driver gostdb.DB, locked bool, err error) { } // NewExploitDB returns db client for Exploit -func NewExploitDB(cnf DBClientConf) (driver exploitdb.DB, locked bool, err error) { - if cnf.ExploitCnf.IsFetchViaHTTP() { +func NewExploitDB(cnf config.VulnDictInterface, debugSQL bool) (driver exploitdb.DB, locked bool, err error) { + if cnf.IsFetchViaHTTP() { return nil, false, nil } - path := cnf.ExploitCnf.URL - if cnf.ExploitCnf.Type == "sqlite3" { - path = cnf.ExploitCnf.SQLite3Path - - if _, err := os.Stat(path); os.IsNotExist(err) { - logging.Log.Warnf("--exploitdb-path=%s file not found. Fetch go-exploit-db before reporting if you want to display exploit codes of detected CVE-IDs. For details, see `https://github.com/vulsio/go-exploitdb`", path) - return nil, false, nil - } + path := cnf.GetURL() + if cnf.GetType() == "sqlite3" { + path = cnf.GetSQLite3Path() } - - logging.Log.Debugf("Open exploit db (%s): %s", cnf.ExploitCnf.Type, path) - if driver, locked, err = exploitdb.NewDB(cnf.ExploitCnf.Type, path, cnf.DebugSQL); err != nil { + if driver, locked, err = exploitdb.NewDB(cnf.GetType(), path, debugSQL); err != nil { if locked { return nil, true, xerrors.Errorf("exploitDB is locked. err: %w", err) } @@ -191,22 +150,15 @@ func NewExploitDB(cnf DBClientConf) (driver exploitdb.DB, locked bool, err error } // NewMetasploitDB returns db client for Metasploit -func NewMetasploitDB(cnf DBClientConf) (driver metasploitdb.DB, locked bool, err error) { - if cnf.MetasploitCnf.IsFetchViaHTTP() { +func NewMetasploitDB(cnf config.VulnDictInterface, debugSQL bool) (driver metasploitdb.DB, locked bool, err error) { + if cnf.IsFetchViaHTTP() { return nil, false, nil } - path := cnf.MetasploitCnf.URL - if cnf.MetasploitCnf.Type == "sqlite3" { - path = cnf.MetasploitCnf.SQLite3Path - - if _, err := os.Stat(path); os.IsNotExist(err) { - logging.Log.Warnf("--msfdb-path=%s file not found. Fetch go-msfdb before reporting if you want to display metasploit modules of detected CVE-IDs. For details, see `https://github.com/takuzoo3868/go-msfdb`", path) - return nil, false, nil - } + path := cnf.GetURL() + if cnf.GetType() == "sqlite3" { + path = cnf.GetSQLite3Path() } - - logging.Log.Debugf("Open metasploit db (%s): %s", cnf.MetasploitCnf.Type, path) - if driver, locked, err = metasploitdb.NewDB(cnf.MetasploitCnf.Type, path, cnf.DebugSQL, false); err != nil { + if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, debugSQL, false); err != nil { if locked { return nil, true, xerrors.Errorf("metasploitDB is locked. err: %w", err) } diff --git a/subcmds/report.go b/subcmds/report.go index 644fbfbc..196987eb 100644 --- a/subcmds/report.go +++ b/subcmds/report.go @@ -243,37 +243,14 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} r.ServerInfo(), pp.Sprintf("%s", c.Conf.Servers[r.ServerName])) } - for _, cnf := range []c.VulnDictInterface{ + dbclient, err := detector.NewDBClient( &c.Conf.CveDict, &c.Conf.OvalDict, &c.Conf.Gost, &c.Conf.Exploit, &c.Conf.Metasploit, - } { - if err := cnf.Validate(); err != nil { - logging.Log.Errorf("Failed to validate VulnDict: %+v", err) - return subcommands.ExitFailure - } - - if err := cnf.CheckHTTPHealth(); err != nil { - logging.Log.Errorf("Run as server mode before reporting: %+v", err) - return subcommands.ExitFailure - } - } - - // TODO move into fillcveInfos - dbclient, locked, err := detector.NewDBClient(detector.DBClientConf{ - CveDictCnf: c.Conf.CveDict, - OvalDictCnf: c.Conf.OvalDict, - GostCnf: c.Conf.Gost, - ExploitCnf: c.Conf.Exploit, - MetasploitCnf: c.Conf.Metasploit, - DebugSQL: c.Conf.DebugSQL, - }) - if locked { - logging.Log.Errorf("SQLite3 is locked. Close other DB connections and try again. err: %+v", err) - return subcommands.ExitFailure - } + c.Conf.DebugSQL, + ) if err != nil { logging.Log.Errorf("Failed to init DB Clients. err: %+v", err) return subcommands.ExitFailure @@ -284,7 +261,6 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} } }() - // TODO pass conf by arg if res, err = detector.Detect(*dbclient, res, dir); err != nil { logging.Log.Errorf("%+v", err) return subcommands.ExitFailure diff --git a/subcmds/server.go b/subcmds/server.go index de609509..1563ee8a 100644 --- a/subcmds/server.go +++ b/subcmds/server.go @@ -99,36 +99,14 @@ func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} return subcommands.ExitUsageError } - for _, cnf := range []c.VulnDictInterface{ + dbclient, err := detector.NewDBClient( &c.Conf.CveDict, &c.Conf.OvalDict, &c.Conf.Gost, &c.Conf.Exploit, &c.Conf.Metasploit, - } { - if err := cnf.Validate(); err != nil { - logging.Log.Errorf("Failed to validate VulnDict: %+v", err) - return subcommands.ExitFailure - } - - if err := cnf.CheckHTTPHealth(); err != nil { - logging.Log.Errorf("Run as server mode before reporting: %+v", err) - return subcommands.ExitFailure - } - } - - dbclient, locked, err := detector.NewDBClient(detector.DBClientConf{ - CveDictCnf: c.Conf.CveDict, - OvalDictCnf: c.Conf.OvalDict, - GostCnf: c.Conf.Gost, - ExploitCnf: c.Conf.Exploit, - MetasploitCnf: c.Conf.Metasploit, - DebugSQL: c.Conf.DebugSQL, - }) - if locked { - logging.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %+v", err) - return subcommands.ExitFailure - } + c.Conf.DebugSQL, + ) if err != nil { logging.Log.Errorf("Failed to init DB Clients. err: %+v", err) return subcommands.ExitFailure diff --git a/subcmds/tui.go b/subcmds/tui.go index 6e0d8d53..432e9afe 100644 --- a/subcmds/tui.go +++ b/subcmds/tui.go @@ -138,36 +138,14 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s } logging.Log.Infof("Loaded: %s", dir) - for _, cnf := range []c.VulnDictInterface{ + dbclient, err := detector.NewDBClient( &c.Conf.CveDict, &c.Conf.OvalDict, &c.Conf.Gost, &c.Conf.Exploit, &c.Conf.Metasploit, - } { - if err := cnf.Validate(); err != nil { - logging.Log.Errorf("Failed to validate VulnDict: %+v", err) - return subcommands.ExitFailure - } - - if err := cnf.CheckHTTPHealth(); err != nil { - logging.Log.Errorf("Run as server mode before reporting: %+v", err) - return subcommands.ExitFailure - } - } - - dbclient, locked, err := detector.NewDBClient(detector.DBClientConf{ - CveDictCnf: c.Conf.CveDict, - OvalDictCnf: c.Conf.OvalDict, - GostCnf: c.Conf.Gost, - ExploitCnf: c.Conf.Exploit, - MetasploitCnf: c.Conf.Metasploit, - DebugSQL: c.Conf.DebugSQL, - }) - if locked { - logging.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %+v", err) - return subcommands.ExitFailure - } + c.Conf.DebugSQL, + ) if err != nil { logging.Log.Errorf("Failed to init DB Clients. err: %+v", err) return subcommands.ExitFailure