23
scan/base.go
23
scan/base.go
@@ -199,24 +199,23 @@ func (l *base) parseLxdPs(stdout string) (containers []config.Container, err err
|
||||
return
|
||||
}
|
||||
|
||||
func (l *base) detectPlatform() error {
|
||||
func (l *base) detectPlatform() {
|
||||
ok, instanceID, err := l.detectRunningOnAws()
|
||||
if err != nil {
|
||||
return err
|
||||
l.setPlatform(models.Platform{Name: "other"})
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
l.setPlatform(models.Platform{
|
||||
Name: "aws",
|
||||
InstanceID: instanceID,
|
||||
})
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
//TODO Azure, GCP...
|
||||
l.setPlatform(models.Platform{
|
||||
Name: "other",
|
||||
})
|
||||
return nil
|
||||
l.setPlatform(models.Platform{Name: "other"})
|
||||
return
|
||||
}
|
||||
|
||||
func (l base) detectRunningOnAws() (ok bool, instanceID string, err error) {
|
||||
@@ -271,7 +270,7 @@ func (l base) isAwsInstanceID(str string) bool {
|
||||
return awsInstanceIDPattern.MatchString(str)
|
||||
}
|
||||
|
||||
func (l *base) convertToModel() (models.ScanResult, error) {
|
||||
func (l *base) convertToModel() models.ScanResult {
|
||||
for _, p := range l.VulnInfos {
|
||||
sort.Sort(models.PackageInfosByName(p.Packages))
|
||||
}
|
||||
@@ -283,6 +282,11 @@ func (l *base) convertToModel() (models.ScanResult, error) {
|
||||
Image: l.ServerInfo.Container.Image,
|
||||
}
|
||||
|
||||
errs := []string{}
|
||||
for _, e := range l.errs {
|
||||
errs = append(errs, fmt.Sprintf("%s", e))
|
||||
}
|
||||
|
||||
return models.ScanResult{
|
||||
ServerName: l.ServerInfo.ServerName,
|
||||
ScannedAt: time.Now(),
|
||||
@@ -293,7 +297,8 @@ func (l *base) convertToModel() (models.ScanResult, error) {
|
||||
ScannedCves: l.VulnInfos,
|
||||
Packages: l.Packages,
|
||||
Optional: l.ServerInfo.Optional,
|
||||
}, nil
|
||||
Errors: errs,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *base) setErrs(errs []error) {
|
||||
|
||||
@@ -56,7 +56,7 @@ func detectDebian(c config.ServerInfo) (itsMe bool, deb osTypeInterface, err err
|
||||
return false, deb, fmt.Errorf(
|
||||
"Unable to connect via SSH. Check SSH settings. %s", r)
|
||||
}
|
||||
Log.Debugf("Not Debian like Linux. %s", r)
|
||||
util.Log.Debugf("Not Debian like Linux. %s", r)
|
||||
return false, deb, nil
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func detectDebian(c config.ServerInfo) (itsMe bool, deb osTypeInterface, err err
|
||||
|
||||
if len(result) == 0 {
|
||||
deb.setDistro("debian/ubuntu", "unknown")
|
||||
Log.Warnf(
|
||||
util.Log.Warnf(
|
||||
"Unknown Debian/Ubuntu version. lsb_release -ir: %s", r)
|
||||
} else {
|
||||
distro := strings.ToLower(trim(result[1]))
|
||||
@@ -88,7 +88,7 @@ func detectDebian(c config.ServerInfo) (itsMe bool, deb osTypeInterface, err err
|
||||
re := regexp.MustCompile(`(?s)^DISTRIB_ID=(.+?)\n*DISTRIB_RELEASE=(.+?)\n.*$`)
|
||||
result := re.FindStringSubmatch(trim(r.Stdout))
|
||||
if len(result) == 0 {
|
||||
Log.Warnf(
|
||||
util.Log.Warnf(
|
||||
"Unknown Debian/Ubuntu. cat /etc/lsb-release: %s", r)
|
||||
deb.setDistro("debian/ubuntu", "unknown")
|
||||
} else {
|
||||
@@ -105,7 +105,7 @@ func detectDebian(c config.ServerInfo) (itsMe bool, deb osTypeInterface, err err
|
||||
return true, deb, nil
|
||||
}
|
||||
|
||||
Log.Debugf("Not Debian like Linux: %s", c.ServerName)
|
||||
util.Log.Debugf("Not Debian like Linux: %s", c.ServerName)
|
||||
return false, deb, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -71,35 +71,30 @@ func (s execResult) isSuccess(expectedStatusCodes ...int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Sudo is Const value for sudo mode
|
||||
// sudo is Const value for sudo mode
|
||||
const sudo = true
|
||||
|
||||
// NoSudo is Const value for normal user mode
|
||||
// noSudo is Const value for normal user mode
|
||||
const noSudo = false
|
||||
|
||||
func parallelSSHExec(fn func(osTypeInterface) error, timeoutSec ...int) (errs []error) {
|
||||
resChan := make(chan string, len(servers))
|
||||
errChan := make(chan error, len(servers))
|
||||
defer close(errChan)
|
||||
// Issue commands to the target servers in parallel via SSH or local execution. If execution fails, the server will be excluded from the target server list(servers) and added to the error server list(errServers).
|
||||
func parallelExec(fn func(osTypeInterface) error, timeoutSec ...int) {
|
||||
resChan := make(chan osTypeInterface, len(servers))
|
||||
defer close(resChan)
|
||||
|
||||
for _, s := range servers {
|
||||
go func(s osTypeInterface) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
logrus.Debugf("Panic: %s on %s",
|
||||
util.Log.Debugf("Panic: %s on %s",
|
||||
p, s.getServerInfo().GetServerName())
|
||||
}
|
||||
}()
|
||||
if err := fn(s); err != nil {
|
||||
errChan <- fmt.Errorf("%s@%s:%s: %s",
|
||||
s.getServerInfo().User,
|
||||
s.getServerInfo().Host,
|
||||
s.getServerInfo().Port,
|
||||
err,
|
||||
)
|
||||
s.setErrs([]error{err})
|
||||
resChan <- s
|
||||
} else {
|
||||
resChan <- s.getServerInfo().GetServerName()
|
||||
resChan <- s
|
||||
}
|
||||
}(s)
|
||||
}
|
||||
@@ -111,40 +106,44 @@ func parallelSSHExec(fn func(osTypeInterface) error, timeoutSec ...int) (errs []
|
||||
timeout = timeoutSec[0]
|
||||
}
|
||||
|
||||
var snames []string
|
||||
var successes []osTypeInterface
|
||||
isTimedout := false
|
||||
for i := 0; i < len(servers); i++ {
|
||||
select {
|
||||
case s := <-resChan:
|
||||
snames = append(snames, s)
|
||||
case err := <-errChan:
|
||||
errs = append(errs, err)
|
||||
if len(s.getErrs()) == 0 {
|
||||
successes = append(successes, s)
|
||||
} else {
|
||||
util.Log.Errorf("Error: %s, err: %s",
|
||||
s.getServerInfo().GetServerName(), s.getErrs())
|
||||
errServers = append(errServers, s)
|
||||
}
|
||||
case <-time.After(time.Duration(timeout) * time.Second):
|
||||
isTimedout = true
|
||||
}
|
||||
}
|
||||
|
||||
// collect timed out servernames
|
||||
var timedoutSnames []string
|
||||
if isTimedout {
|
||||
// set timed out error and append to errServers
|
||||
for _, s := range servers {
|
||||
name := s.getServerInfo().GetServerName()
|
||||
found := false
|
||||
for _, t := range snames {
|
||||
if name == t {
|
||||
for _, ss := range successes {
|
||||
if name == ss.getServerInfo().GetServerName() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
timedoutSnames = append(timedoutSnames, name)
|
||||
msg := fmt.Sprintf("Timed out: %s",
|
||||
s.getServerInfo().GetServerName())
|
||||
util.Log.Errorf(msg)
|
||||
s.setErrs([]error{fmt.Errorf(msg)})
|
||||
errServers = append(errServers, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
if isTimedout {
|
||||
errs = append(errs, fmt.Errorf(
|
||||
"Timed out: %s", timedoutSnames))
|
||||
}
|
||||
servers = successes
|
||||
return
|
||||
}
|
||||
|
||||
@@ -55,13 +55,13 @@ func detectFreebsd(c config.ServerInfo) (itsMe bool, bsd osTypeInterface) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.Debugf("Not FreeBSD. servernam: %s", c.ServerName)
|
||||
util.Log.Debugf("Not FreeBSD. servernam: %s", c.ServerName)
|
||||
return false, bsd
|
||||
}
|
||||
|
||||
func (o *bsd) checkIfSudoNoPasswd() error {
|
||||
// FreeBSD doesn't need root privilege
|
||||
o.log.Infof("sudo ... OK")
|
||||
o.log.Infof("sudo ... No need")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func detectRedhat(c config.ServerInfo) (itsMe bool, red osTypeInterface) {
|
||||
|
||||
if r := exec(c, "ls /etc/fedora-release", noSudo); r.isSuccess() {
|
||||
red.setDistro("fedora", "unknown")
|
||||
Log.Warn("Fedora not tested yet: %s", r)
|
||||
util.Log.Warn("Fedora not tested yet: %s", r)
|
||||
return true, red
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ func detectRedhat(c config.ServerInfo) (itsMe bool, red osTypeInterface) {
|
||||
re := regexp.MustCompile(`(.*) release (\d[\d.]*)`)
|
||||
result := re.FindStringSubmatch(strings.TrimSpace(r.Stdout))
|
||||
if len(result) != 3 {
|
||||
Log.Warn("Failed to parse RedHat/CentOS version: %s", r)
|
||||
util.Log.Warn("Failed to parse RedHat/CentOS version: %s", r)
|
||||
return true, red
|
||||
}
|
||||
|
||||
@@ -92,11 +92,16 @@ func detectRedhat(c config.ServerInfo) (itsMe bool, red osTypeInterface) {
|
||||
return true, red
|
||||
}
|
||||
|
||||
Log.Debugf("Not RedHat like Linux. servername: %s", c.ServerName)
|
||||
util.Log.Debugf("Not RedHat like Linux. servername: %s", c.ServerName)
|
||||
return false, red
|
||||
}
|
||||
|
||||
func (o *redhat) checkIfSudoNoPasswd() error {
|
||||
if !o.sudo() {
|
||||
o.log.Infof("sudo ... No need")
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := "yum --version"
|
||||
if o.Distro.Family == "centos" {
|
||||
cmd = "echo N | " + cmd
|
||||
@@ -117,7 +122,6 @@ func (o *redhat) checkIfSudoNoPasswd() error {
|
||||
func (o *redhat) checkDependencies() error {
|
||||
switch o.Distro.Family {
|
||||
case "rhel", "amazon":
|
||||
// o.log.Infof("Nothing to do")
|
||||
return nil
|
||||
|
||||
case "centos":
|
||||
|
||||
@@ -25,17 +25,14 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/future-architect/vuls/cache"
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/report"
|
||||
"github.com/future-architect/vuls/util"
|
||||
)
|
||||
|
||||
// Log for localhsot
|
||||
var Log *logrus.Entry
|
||||
|
||||
var servers []osTypeInterface
|
||||
var servers, errServers []osTypeInterface
|
||||
|
||||
// Base Interface of redhat, debian, freebsd
|
||||
type osTypeInterface interface {
|
||||
@@ -50,13 +47,13 @@ type osTypeInterface interface {
|
||||
getLackDependencies() []string
|
||||
|
||||
checkIfSudoNoPasswd() error
|
||||
detectPlatform() error
|
||||
detectPlatform()
|
||||
getPlatform() models.Platform
|
||||
|
||||
checkRequiredPackagesInstalled() error
|
||||
scanPackages() error
|
||||
install() error
|
||||
convertToModel() (models.ScanResult, error)
|
||||
convertToModel() models.ScanResult
|
||||
|
||||
runningContainers() ([]config.Container, error)
|
||||
exitedContainers() ([]config.Container, error)
|
||||
@@ -89,33 +86,32 @@ func detectOS(c config.ServerInfo) (osType osTypeInterface) {
|
||||
|
||||
itsMe, osType, fatalErr = detectDebian(c)
|
||||
if fatalErr != nil {
|
||||
osType.setServerInfo(c)
|
||||
osType.setErrs([]error{fatalErr})
|
||||
return
|
||||
} else if itsMe {
|
||||
Log.Debugf("Debian like Linux. Host: %s:%s", c.Host, c.Port)
|
||||
}
|
||||
|
||||
if itsMe {
|
||||
util.Log.Debugf("Debian like Linux. Host: %s:%s", c.Host, c.Port)
|
||||
return
|
||||
}
|
||||
|
||||
if itsMe, osType = detectRedhat(c); itsMe {
|
||||
Log.Debugf("Redhat like Linux. Host: %s:%s", c.Host, c.Port)
|
||||
util.Log.Debugf("Redhat like Linux. Host: %s:%s", c.Host, c.Port)
|
||||
return
|
||||
}
|
||||
|
||||
if itsMe, osType = detectFreebsd(c); itsMe {
|
||||
Log.Debugf("FreeBSD. Host: %s:%s", c.Host, c.Port)
|
||||
util.Log.Debugf("FreeBSD. Host: %s:%s", c.Host, c.Port)
|
||||
return
|
||||
}
|
||||
|
||||
//TODO darwin https://github.com/mizzy/specinfra/blob/master/lib/specinfra/helper/detect_os/darwin.rb
|
||||
|
||||
osType.setServerInfo(c)
|
||||
osType.setErrs([]error{fmt.Errorf("Unknown OS Type")})
|
||||
return
|
||||
}
|
||||
|
||||
// PrintSSHableServerNames print SSH-able servernames
|
||||
func PrintSSHableServerNames() {
|
||||
Log.Info("SSH-able servers are below...")
|
||||
util.Log.Info("SSH-able servers are below...")
|
||||
for _, s := range servers {
|
||||
if s.getServerInfo().IsContainer() {
|
||||
fmt.Printf("%s@%s ",
|
||||
@@ -130,67 +126,74 @@ func PrintSSHableServerNames() {
|
||||
}
|
||||
|
||||
// InitServers detect the kind of OS distribution of target servers
|
||||
func InitServers(localLogger *logrus.Entry) error {
|
||||
Log = localLogger
|
||||
servers = detectServerOSes()
|
||||
func InitServers() error {
|
||||
servers, errServers = detectServerOSes()
|
||||
if len(servers) == 0 {
|
||||
return fmt.Errorf("No scannable servers")
|
||||
}
|
||||
|
||||
containers := detectContainerOSes()
|
||||
actives, inactives := detectContainerOSes()
|
||||
if config.Conf.ContainersOnly {
|
||||
servers = containers
|
||||
servers = actives
|
||||
errServers = inactives
|
||||
} else {
|
||||
servers = append(servers, containers...)
|
||||
servers = append(servers, actives...)
|
||||
errServers = append(errServers, inactives...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func detectServerOSes() (sshAbleOses []osTypeInterface) {
|
||||
Log.Info("Detecting OS of servers... ")
|
||||
func detectServerOSes() (servers, errServers []osTypeInterface) {
|
||||
util.Log.Info("Detecting OS of servers... ")
|
||||
osTypeChan := make(chan osTypeInterface, len(config.Conf.Servers))
|
||||
defer close(osTypeChan)
|
||||
for _, s := range config.Conf.Servers {
|
||||
go func(s config.ServerInfo) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
Log.Debugf("Panic: %s on %s", p, s.ServerName)
|
||||
util.Log.Debugf("Panic: %s on %s", p, s.ServerName)
|
||||
}
|
||||
}()
|
||||
osTypeChan <- detectOS(s)
|
||||
}(s)
|
||||
}
|
||||
|
||||
var oses []osTypeInterface
|
||||
timeout := time.After(30 * time.Second)
|
||||
for i := 0; i < len(config.Conf.Servers); i++ {
|
||||
select {
|
||||
case res := <-osTypeChan:
|
||||
oses = append(oses, res)
|
||||
if 0 < len(res.getErrs()) {
|
||||
Log.Errorf("(%d/%d) Failed: %s, err: %s",
|
||||
errServers = append(errServers, res)
|
||||
util.Log.Errorf("(%d/%d) Failed: %s, err: %s",
|
||||
i+1, len(config.Conf.Servers),
|
||||
res.getServerInfo().ServerName,
|
||||
res.getErrs())
|
||||
} else {
|
||||
Log.Infof("(%d/%d) Detected: %s: %s",
|
||||
servers = append(servers, res)
|
||||
util.Log.Infof("(%d/%d) Detected: %s: %s",
|
||||
i+1, len(config.Conf.Servers),
|
||||
res.getServerInfo().ServerName,
|
||||
res.getDistro())
|
||||
}
|
||||
case <-timeout:
|
||||
msg := "Timed out while detecting servers"
|
||||
Log.Error(msg)
|
||||
for servername := range config.Conf.Servers {
|
||||
util.Log.Error(msg)
|
||||
for servername, sInfo := range config.Conf.Servers {
|
||||
found := false
|
||||
for _, o := range oses {
|
||||
for _, o := range append(servers, errServers...) {
|
||||
if servername == o.getServerInfo().ServerName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
Log.Errorf("(%d/%d) Timed out: %s",
|
||||
u := &unknown{}
|
||||
u.setServerInfo(sInfo)
|
||||
u.setErrs([]error{
|
||||
fmt.Errorf("Timed out"),
|
||||
})
|
||||
errServers = append(errServers, u)
|
||||
util.Log.Errorf("(%d/%d) Timed out: %s",
|
||||
i+1, len(config.Conf.Servers),
|
||||
servername)
|
||||
i++
|
||||
@@ -198,24 +201,18 @@ func detectServerOSes() (sshAbleOses []osTypeInterface) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, o := range oses {
|
||||
if len(o.getErrs()) == 0 {
|
||||
sshAbleOses = append(sshAbleOses, o)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func detectContainerOSes() (actives []osTypeInterface) {
|
||||
Log.Info("Detecting OS of containers... ")
|
||||
func detectContainerOSes() (actives, inactives []osTypeInterface) {
|
||||
util.Log.Info("Detecting OS of containers... ")
|
||||
osTypesChan := make(chan []osTypeInterface, len(servers))
|
||||
defer close(osTypesChan)
|
||||
for _, s := range servers {
|
||||
go func(s osTypeInterface) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
Log.Debugf("Panic: %s on %s",
|
||||
util.Log.Debugf("Panic: %s on %s",
|
||||
p, s.getServerInfo().GetServerName())
|
||||
}
|
||||
}()
|
||||
@@ -223,7 +220,6 @@ func detectContainerOSes() (actives []osTypeInterface) {
|
||||
}(s)
|
||||
}
|
||||
|
||||
var oses []osTypeInterface
|
||||
timeout := time.After(30 * time.Second)
|
||||
for i := 0; i < len(servers); i++ {
|
||||
select {
|
||||
@@ -231,36 +227,38 @@ func detectContainerOSes() (actives []osTypeInterface) {
|
||||
for _, osi := range res {
|
||||
sinfo := osi.getServerInfo()
|
||||
if 0 < len(osi.getErrs()) {
|
||||
Log.Errorf("Failed: %s err: %s", sinfo.ServerName, osi.getErrs())
|
||||
inactives = append(inactives, osi)
|
||||
util.Log.Errorf("Failed: %s err: %s", sinfo.ServerName, osi.getErrs())
|
||||
continue
|
||||
}
|
||||
oses = append(oses, osi)
|
||||
Log.Infof("Detected: %s@%s: %s",
|
||||
actives = append(actives, osi)
|
||||
util.Log.Infof("Detected: %s@%s: %s",
|
||||
sinfo.Container.Name, sinfo.ServerName, osi.getDistro())
|
||||
}
|
||||
case <-timeout:
|
||||
msg := "Timed out while detecting containers"
|
||||
Log.Error(msg)
|
||||
for servername := range config.Conf.Servers {
|
||||
util.Log.Error(msg)
|
||||
for servername, sInfo := range config.Conf.Servers {
|
||||
found := false
|
||||
for _, o := range oses {
|
||||
for _, o := range append(actives, inactives...) {
|
||||
if servername == o.getServerInfo().ServerName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
Log.Errorf("Timed out: %s", servername)
|
||||
u := &unknown{}
|
||||
u.setServerInfo(sInfo)
|
||||
u.setErrs([]error{
|
||||
fmt.Errorf("Timed out"),
|
||||
})
|
||||
inactives = append(inactives)
|
||||
util.Log.Errorf("Timed out: %s", servername)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, o := range oses {
|
||||
if len(o.getErrs()) == 0 {
|
||||
actives = append(actives, o)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -339,28 +337,20 @@ func detectContainerOSesOnServer(containerHost osTypeInterface) (oses []osTypeIn
|
||||
}
|
||||
|
||||
// CheckIfSudoNoPasswd checks whether vuls can sudo with nopassword via SSH
|
||||
func CheckIfSudoNoPasswd(localLogger *logrus.Entry) error {
|
||||
func CheckIfSudoNoPasswd() {
|
||||
timeoutSec := 15
|
||||
errs := parallelSSHExec(func(o osTypeInterface) error {
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
return o.checkIfSudoNoPasswd()
|
||||
}, timeoutSec)
|
||||
|
||||
if 0 < len(errs) {
|
||||
return fmt.Errorf(fmt.Sprintf("%s", errs))
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
// DetectPlatforms detects the platform of each servers.
|
||||
func DetectPlatforms(localLogger *logrus.Entry) {
|
||||
errs := detectPlatforms()
|
||||
if 0 < len(errs) {
|
||||
// Only logging
|
||||
Log.Warnf("Failed to detect platforms. err: %v", errs)
|
||||
}
|
||||
func DetectPlatforms() {
|
||||
detectPlatforms()
|
||||
for i, s := range servers {
|
||||
if s.getServerInfo().IsContainer() {
|
||||
Log.Infof("(%d/%d) %s on %s is running on %s",
|
||||
util.Log.Infof("(%d/%d) %s on %s is running on %s",
|
||||
i+1, len(servers),
|
||||
s.getServerInfo().Container.Name,
|
||||
s.getServerInfo().ServerName,
|
||||
@@ -368,7 +358,7 @@ func DetectPlatforms(localLogger *logrus.Entry) {
|
||||
)
|
||||
|
||||
} else {
|
||||
Log.Infof("(%d/%d) %s is running on %s",
|
||||
util.Log.Infof("(%d/%d) %s is running on %s",
|
||||
i+1, len(servers),
|
||||
s.getServerInfo().ServerName,
|
||||
s.getPlatform().Name,
|
||||
@@ -378,52 +368,68 @@ func DetectPlatforms(localLogger *logrus.Entry) {
|
||||
return
|
||||
}
|
||||
|
||||
func detectPlatforms() []error {
|
||||
func detectPlatforms() {
|
||||
timeoutSec := 1 * 60
|
||||
return parallelSSHExec(func(o osTypeInterface) error {
|
||||
return o.detectPlatform()
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
o.detectPlatform()
|
||||
// Logging only if platform can not be specified
|
||||
return nil
|
||||
}, timeoutSec)
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare installs requred packages to scan vulnerabilities.
|
||||
func Prepare() []error {
|
||||
errs := parallelSSHExec(func(o osTypeInterface) error {
|
||||
func Prepare() error {
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
if err := o.checkDependencies(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if len(errs) != 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
var targets []osTypeInterface
|
||||
var targets, nonTargets []osTypeInterface
|
||||
for _, s := range servers {
|
||||
deps := s.getLackDependencies()
|
||||
if len(deps) != 0 {
|
||||
targets = append(targets, s)
|
||||
} else {
|
||||
nonTargets = append(nonTargets, s)
|
||||
}
|
||||
}
|
||||
if len(targets) == 0 {
|
||||
Log.Info("No need to install dependencies")
|
||||
if 0 < len(nonTargets) {
|
||||
util.Log.Info("The following servers were already installed dependencies")
|
||||
for _, s := range nonTargets {
|
||||
util.Log.Infof(" - %s", s.getServerInfo().GetServerName())
|
||||
}
|
||||
}
|
||||
|
||||
if 0 < len(errServers) {
|
||||
util.Log.Error("Some errors occurred in the following servers")
|
||||
for _, s := range errServers {
|
||||
util.Log.Errorf(" - %s", s.getServerInfo().GetServerName())
|
||||
}
|
||||
} else {
|
||||
util.Log.Info("Success")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Log.Info("The following servers need dependencies installed")
|
||||
util.Log.Info("The following servers need to install dependencies")
|
||||
for _, s := range targets {
|
||||
for _, d := range s.getLackDependencies() {
|
||||
Log.Infof(" - %s on %s", d, s.getServerInfo().GetServerName())
|
||||
util.Log.Infof(" - %s on %s", d, s.getServerInfo().GetServerName())
|
||||
}
|
||||
}
|
||||
|
||||
if !config.Conf.AssumeYes {
|
||||
Log.Info("Is this ok to install dependencies on the servers? [y/N]")
|
||||
util.Log.Info("Is this ok to install dependencies on the servers? [y/N]")
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
text, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
return err
|
||||
}
|
||||
switch strings.TrimSpace(text) {
|
||||
case "", "N", "n":
|
||||
@@ -431,62 +437,81 @@ func Prepare() []error {
|
||||
case "y", "Y":
|
||||
goto yes
|
||||
default:
|
||||
Log.Info("Please enter y or N")
|
||||
util.Log.Info("Please enter y or N")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yes:
|
||||
servers = targets
|
||||
errs = parallelSSHExec(func(o osTypeInterface) error {
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
if err := o.install(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if len(errs) != 0 {
|
||||
return errs
|
||||
|
||||
if 0 < len(servers) {
|
||||
util.Log.Info("Successfully installed in the followring servers")
|
||||
for _, s := range servers {
|
||||
util.Log.Infof(" - %s", s.getServerInfo().GetServerName())
|
||||
}
|
||||
}
|
||||
|
||||
if 0 < len(nonTargets) {
|
||||
util.Log.Info("The following servers were already installed dependencies")
|
||||
for _, s := range nonTargets {
|
||||
util.Log.Infof(" - %s", s.getServerInfo().GetServerName())
|
||||
}
|
||||
}
|
||||
|
||||
if 0 < len(errServers) {
|
||||
util.Log.Error("Some errors occurred in the following servers")
|
||||
for _, s := range errServers {
|
||||
util.Log.Errorf(" - %s", s.getServerInfo().GetServerName())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errServers) == 0 {
|
||||
util.Log.Info("Success")
|
||||
} else {
|
||||
util.Log.Error("Failure")
|
||||
}
|
||||
Log.Info("All dependencies were installed correctly")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Scan scan
|
||||
func Scan() []error {
|
||||
func Scan() error {
|
||||
if len(servers) == 0 {
|
||||
return []error{fmt.Errorf("No server defined. Check the configuration")}
|
||||
return fmt.Errorf("No server defined. Check the configuration")
|
||||
}
|
||||
|
||||
Log.Info("Check required packages for scanning...")
|
||||
if errs := checkRequiredPackagesInstalled(); errs != nil {
|
||||
Log.Error("Please execute with [prepare] subcommand to install required packages before scanning")
|
||||
return errs
|
||||
}
|
||||
util.Log.Info("Check required packages for scanning...")
|
||||
checkRequiredPackagesInstalled()
|
||||
|
||||
if err := setupCangelogCache(); err != nil {
|
||||
return []error{err}
|
||||
if err := setupChangelogCache(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if cache.DB != nil {
|
||||
cache.DB.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
Log.Info("Scanning vulnerable OS packages...")
|
||||
util.Log.Info("Scanning vulnerable OS packages...")
|
||||
scannedAt := time.Now()
|
||||
dir, err := ensureResultDir(scannedAt)
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
return err
|
||||
}
|
||||
if errs := scanVulns(dir, scannedAt); errs != nil {
|
||||
return errs
|
||||
if err := scanVulns(dir, scannedAt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupCangelogCache() error {
|
||||
func setupChangelogCache() error {
|
||||
needToSetupCache := false
|
||||
for _, s := range servers {
|
||||
switch s.getDistro().Family {
|
||||
@@ -496,7 +521,7 @@ func setupCangelogCache() error {
|
||||
}
|
||||
}
|
||||
if needToSetupCache {
|
||||
if err := cache.SetupBolt(config.Conf.CacheDBPath, Log); err != nil {
|
||||
if err := cache.SetupBolt(config.Conf.CacheDBPath, util.Log); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -505,28 +530,24 @@ func setupCangelogCache() error {
|
||||
|
||||
func checkRequiredPackagesInstalled() []error {
|
||||
timeoutSec := 30 * 60
|
||||
return parallelSSHExec(func(o osTypeInterface) error {
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
return o.checkRequiredPackagesInstalled()
|
||||
}, timeoutSec)
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanVulns(jsonDir string, scannedAt time.Time) []error {
|
||||
func scanVulns(jsonDir string, scannedAt time.Time) error {
|
||||
var results models.ScanResults
|
||||
timeoutSec := 120 * 60
|
||||
errs := parallelSSHExec(func(o osTypeInterface) error {
|
||||
if err := o.scanPackages(); err != nil {
|
||||
return err
|
||||
}
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
return o.scanPackages()
|
||||
}, timeoutSec)
|
||||
|
||||
r, err := o.convertToModel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range append(servers, errServers...) {
|
||||
r := s.convertToModel()
|
||||
r.ScannedAt = scannedAt
|
||||
results = append(results, r)
|
||||
|
||||
return nil
|
||||
}, timeoutSec)
|
||||
}
|
||||
|
||||
config.Conf.FormatJSON = true
|
||||
ws := []report.ResultWriter{
|
||||
@@ -534,14 +555,9 @@ func scanVulns(jsonDir string, scannedAt time.Time) []error {
|
||||
}
|
||||
for _, w := range ws {
|
||||
if err := w.Write(results...); err != nil {
|
||||
return []error{
|
||||
fmt.Errorf("Failed to write summary report: %s", err),
|
||||
}
|
||||
return fmt.Errorf("Failed to write summary report: %s", err)
|
||||
}
|
||||
}
|
||||
if errs != nil {
|
||||
return errs
|
||||
}
|
||||
|
||||
report.StdoutWriter{}.WriteScanSummary(results...)
|
||||
return nil
|
||||
|
||||
43
scan/unknownDistro.go
Normal file
43
scan/unknownDistro.go
Normal file
@@ -0,0 +1,43 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package scan
|
||||
|
||||
// inherit OsTypeInterface
|
||||
type unknown struct {
|
||||
base
|
||||
}
|
||||
|
||||
func (o *unknown) checkIfSudoNoPasswd() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o unknown) checkDependencies() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *unknown) install() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *unknown) checkRequiredPackagesInstalled() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *unknown) scanPackages() error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user