Continue scanning even when some hosts have tech issues

see #264
This commit is contained in:
Kota Kanbe
2017-01-31 14:35:16 +09:00
parent 00660485b7
commit 386b97d2be
19 changed files with 447 additions and 311 deletions

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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":

View File

@@ -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
View 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
}