Deprecate prepare subcommand to minimize the root authority #375
This commit is contained in:
@@ -34,7 +34,6 @@ type base struct {
|
||||
Distro config.Distro
|
||||
Platform models.Platform
|
||||
|
||||
lackDependencies []string
|
||||
osPackages
|
||||
|
||||
log *logrus.Entry
|
||||
@@ -77,10 +76,6 @@ func (l base) getPlatform() models.Platform {
|
||||
return l.Platform
|
||||
}
|
||||
|
||||
func (l base) getLackDependencies() []string {
|
||||
return l.lackDependencies
|
||||
}
|
||||
|
||||
func (l base) allContainers() (containers []config.Container, err error) {
|
||||
switch l.ServerInfo.Container.Type {
|
||||
case "", "docker":
|
||||
|
||||
@@ -128,12 +128,14 @@ func trim(str string) string {
|
||||
}
|
||||
|
||||
func (o *debian) checkIfSudoNoPasswd() error {
|
||||
r := o.exec("apt-get -v", noSudo)
|
||||
cmd := util.PrependProxyEnv("apt-get update")
|
||||
o.log.Infof("Checking... sudo %s", cmd)
|
||||
r := o.exec(cmd, sudo)
|
||||
if !r.isSuccess() {
|
||||
o.log.Errorf("sudo error on %s", r)
|
||||
return fmt.Errorf("Failed to sudo: %s", r)
|
||||
}
|
||||
o.log.Infof("sudo ... OK")
|
||||
o.log.Infof("Sudo... Pass")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -145,11 +147,12 @@ func (o *debian) checkDependencies() error {
|
||||
case "debian":
|
||||
// Debian needs aptitude to get changelogs.
|
||||
// Because unable to get changelogs via apt-get changelog on Debian.
|
||||
name := "aptitude"
|
||||
cmd := name + " -h"
|
||||
if r := o.exec(cmd, noSudo); !r.isSuccess() {
|
||||
o.lackDependencies = []string{name}
|
||||
if r := o.exec("test -f /usr/bin/aptitude", noSudo); !r.isSuccess() {
|
||||
msg := fmt.Sprintf("aptitude is not installed: %s", r)
|
||||
o.log.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
o.log.Infof("Dependencies... Pass")
|
||||
return nil
|
||||
|
||||
default:
|
||||
@@ -157,32 +160,6 @@ func (o *debian) checkDependencies() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *debian) install() error {
|
||||
if len(o.lackDependencies) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// apt-get update
|
||||
o.log.Infof("apt-get update...")
|
||||
cmd := util.PrependProxyEnv("apt-get update")
|
||||
if r := o.exec(cmd, sudo); !r.isSuccess() {
|
||||
msg := fmt.Sprintf("Failed to SSH: %s", r)
|
||||
o.log.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
for _, name := range o.lackDependencies {
|
||||
cmd = util.PrependProxyEnv("apt-get install -y " + name)
|
||||
if r := o.exec(cmd, sudo); !r.isSuccess() {
|
||||
msg := fmt.Sprintf("Failed to SSH: %s", r)
|
||||
o.log.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
o.log.Infof("Installed: " + name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *debian) scanPackages() error {
|
||||
var err error
|
||||
var packs []models.PackageInfo
|
||||
@@ -244,17 +221,6 @@ func (o *debian) parseScannedPackagesLine(line string) (name, version string, er
|
||||
return "", "", fmt.Errorf("Unknown format: %s", line)
|
||||
}
|
||||
|
||||
func (o *debian) checkRequiredPackagesInstalled() error {
|
||||
if o.Distro.Family == "debian" {
|
||||
if r := o.exec("test -f /usr/bin/aptitude", noSudo); !r.isSuccess() {
|
||||
msg := fmt.Sprintf("aptitude is not installed: %s", r)
|
||||
o.log.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *debian) scanUnsecurePackages(installed []models.PackageInfo) ([]models.VulnInfo, error) {
|
||||
o.log.Infof("apt-get update...")
|
||||
cmd := util.PrependProxyEnv("apt-get update")
|
||||
|
||||
@@ -327,9 +327,6 @@ func decorateCmd(c conf.ServerInfo, cmd string, sudo bool) string {
|
||||
if sudo && c.User != "root" && !c.IsContainer() {
|
||||
cmd = fmt.Sprintf("sudo -S %s", cmd)
|
||||
cmd = strings.Replace(cmd, "|", "| sudo ", -1)
|
||||
|
||||
// echo command does not need sudo (for CentOS)
|
||||
cmd = strings.Replace(cmd, "sudo -S echo", "echo", -1)
|
||||
}
|
||||
|
||||
// If you are using pipe and you want to detect preprocessing errors, remove comment out
|
||||
|
||||
@@ -69,14 +69,6 @@ func (o *bsd) checkDependencies() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *bsd) install() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *bsd) checkRequiredPackagesInstalled() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *bsd) scanPackages() error {
|
||||
var err error
|
||||
var packs []models.PackageInfo
|
||||
|
||||
126
scan/redhat.go
126
scan/redhat.go
@@ -102,83 +102,97 @@ func (o *redhat) checkIfSudoNoPasswd() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := "yum --version"
|
||||
if o.Distro.Family == "centos" {
|
||||
cmd = "echo N | " + cmd
|
||||
type cmd struct {
|
||||
cmd string
|
||||
expectedStatusCodes []int
|
||||
}
|
||||
r := o.exec(cmd, o.sudo())
|
||||
if !r.isSuccess() {
|
||||
o.log.Errorf("sudo error on %s", r)
|
||||
return fmt.Errorf("Failed to sudo: %s", r)
|
||||
}
|
||||
o.log.Infof("sudo ... OK")
|
||||
return nil
|
||||
}
|
||||
var cmds []cmd
|
||||
var zero = []int{0}
|
||||
|
||||
// CentOS 5 ... yum-changelog
|
||||
// CentOS 6 ... yum-plugin-changelog
|
||||
// CentOS 7 ... yum-plugin-changelog
|
||||
// RHEL, Amazon ... no additinal packages needed
|
||||
func (o *redhat) checkDependencies() error {
|
||||
switch o.Distro.Family {
|
||||
case "rhel", "amazon":
|
||||
return nil
|
||||
|
||||
case "centos":
|
||||
cmds = []cmd{
|
||||
{"yum --changelog --assumeno update yum", []int{0, 1}},
|
||||
}
|
||||
|
||||
case "rhel":
|
||||
majorVersion, err := o.Distro.MajorVersion()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Not implemented yet: %s, err: %s", o.Distro, err)
|
||||
}
|
||||
|
||||
var name = "yum-plugin-changelog"
|
||||
if majorVersion < 6 {
|
||||
name = "yum-changelog"
|
||||
cmds = []cmd{
|
||||
{"yum --color=never repolist", zero},
|
||||
{"yum --color=never check-update", []int{0, 100}},
|
||||
{"yum --color=never list-security --security", zero},
|
||||
{"yum --color=never info-security", zero},
|
||||
}
|
||||
} else {
|
||||
cmds = []cmd{
|
||||
{"yum --color=never repolist", zero},
|
||||
{"yum --color=never check-update", []int{0, 100}},
|
||||
{"yum --color=never --security updateinfo list updates", zero},
|
||||
{"yum --color=never --security updateinfo updates", zero},
|
||||
}
|
||||
}
|
||||
|
||||
cmd := "rpm -q " + name
|
||||
if r := o.exec(cmd, noSudo); r.isSuccess() {
|
||||
return nil
|
||||
}
|
||||
o.lackDependencies = []string{name}
|
||||
return nil
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Not implemented yet: %s", o.Distro)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *redhat) install() error {
|
||||
for _, name := range o.lackDependencies {
|
||||
cmd := util.PrependProxyEnv("yum install -y " + name)
|
||||
if r := o.exec(cmd, sudo); !r.isSuccess() {
|
||||
return fmt.Errorf("Failed to SSH: %s", r)
|
||||
for _, c := range cmds {
|
||||
cmd := util.PrependProxyEnv(c.cmd)
|
||||
o.log.Infof("Checking... sudo %s", cmd)
|
||||
r := o.exec(util.PrependProxyEnv(cmd), o.sudo())
|
||||
if !r.isSuccess(c.expectedStatusCodes...) {
|
||||
o.log.Errorf("Check sudo or proxy settings: %s", r)
|
||||
return fmt.Errorf("Failed to sudo: %s", r)
|
||||
}
|
||||
o.log.Infof("Installed: %s", name)
|
||||
}
|
||||
o.log.Infof("Sudo... Pass")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *redhat) checkRequiredPackagesInstalled() error {
|
||||
if o.Distro.Family == "centos" {
|
||||
majorVersion, err := o.Distro.MajorVersion()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Not implemented yet: %s, err: %s", o.Distro, err)
|
||||
o.log.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
// CentOS 5 ... yum-changelog
|
||||
// CentOS 6, 7 ... yum-plugin-changelog
|
||||
// RHEL 5 ... yum-security
|
||||
// RHEL 6, 7 ... -
|
||||
// Amazon ... -
|
||||
func (o *redhat) checkDependencies() error {
|
||||
var packName string
|
||||
if o.Distro.Family == "amazon" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var packName = "yum-plugin-changelog"
|
||||
majorVersion, err := o.Distro.MajorVersion()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Not implemented yet: %s, err: %s", o.Distro, err)
|
||||
o.log.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
switch o.Distro.Family {
|
||||
case "centos":
|
||||
packName = "yum-plugin-changelog"
|
||||
if majorVersion < 6 {
|
||||
packName = "yum-changelog"
|
||||
}
|
||||
|
||||
cmd := "rpm -q " + packName
|
||||
if r := o.exec(cmd, noSudo); !r.isSuccess() {
|
||||
msg := fmt.Sprintf("%s is not installed", packName)
|
||||
o.log.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
case "rhel":
|
||||
if majorVersion < 6 {
|
||||
packName = "yum-security"
|
||||
} else {
|
||||
// yum-plugin-security is installed by default on RHEL6, 7
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("Not implemented yet: %s", o.Distro)
|
||||
}
|
||||
|
||||
cmd := "rpm -q " + packName
|
||||
if r := o.exec(cmd, noSudo); !r.isSuccess() {
|
||||
msg := fmt.Sprintf("%s is not installed", packName)
|
||||
o.log.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
o.log.Infof("Dependencies... Pass")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -551,7 +565,7 @@ func (o *redhat) getAllChangelog(packInfoList models.PackageInfoList) (stdout st
|
||||
packageNames += fmt.Sprintf("%s ", packInfo.Name)
|
||||
}
|
||||
|
||||
command := "echo N | "
|
||||
command := ""
|
||||
if 0 < len(config.Conf.HTTPProxy) {
|
||||
command += util.ProxyEnv()
|
||||
}
|
||||
@@ -565,7 +579,7 @@ func (o *redhat) getAllChangelog(packInfoList models.PackageInfoList) (stdout st
|
||||
}
|
||||
|
||||
// yum update --changelog doesn't have --color option.
|
||||
command += fmt.Sprintf(" LANGUAGE=en_US.UTF-8 yum %s --changelog update ", yumopts) + packageNames
|
||||
command += fmt.Sprintf(" LANGUAGE=en_US.UTF-8 yum --changelog --assumeno update %s ", yumopts) + packageNames
|
||||
|
||||
r := o.exec(command, sudo)
|
||||
if !r.isSuccess(0, 1) {
|
||||
@@ -647,7 +661,7 @@ func (o *redhat) scanUnsecurePackagesUsingYumPluginSecurity() (models.VulnInfos,
|
||||
|
||||
// get advisoryID(RHSA, ALAS) - CVE IDs
|
||||
if o.Distro.Family == "rhel" && major == 5 {
|
||||
cmd = "yum --color=never info-sec"
|
||||
cmd = "yum --color=never info-security"
|
||||
} else {
|
||||
cmd = "yum --color=never --security updateinfo updates"
|
||||
}
|
||||
|
||||
@@ -18,11 +18,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package scan
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/cache"
|
||||
@@ -38,21 +36,16 @@ var servers, errServers []osTypeInterface
|
||||
type osTypeInterface interface {
|
||||
setServerInfo(config.ServerInfo)
|
||||
getServerInfo() config.ServerInfo
|
||||
|
||||
setDistro(string, string)
|
||||
getDistro() config.Distro
|
||||
|
||||
// checkDependencies checks if dependencies are installed on the target server.
|
||||
checkDependencies() error
|
||||
getLackDependencies() []string
|
||||
|
||||
checkIfSudoNoPasswd() error
|
||||
detectPlatform()
|
||||
getPlatform() models.Platform
|
||||
|
||||
checkRequiredPackagesInstalled() error
|
||||
// checkDependencies checks if dependencies are installed on the target server.
|
||||
checkDependencies() error
|
||||
checkIfSudoNoPasswd() error
|
||||
|
||||
scanPackages() error
|
||||
install() error
|
||||
convertToModel() models.ScanResult
|
||||
|
||||
runningContainers() ([]config.Container, error)
|
||||
@@ -113,7 +106,7 @@ func detectOS(c config.ServerInfo) (osType osTypeInterface) {
|
||||
|
||||
// PrintSSHableServerNames print SSH-able servernames
|
||||
func PrintSSHableServerNames() {
|
||||
util.Log.Info("SSH-able servers are below...")
|
||||
util.Log.Info("Scannable servers are below...")
|
||||
for _, s := range servers {
|
||||
if s.getServerInfo().IsContainer() {
|
||||
fmt.Printf("%s@%s ",
|
||||
@@ -338,9 +331,18 @@ func detectContainerOSesOnServer(containerHost osTypeInterface) (oses []osTypeIn
|
||||
return oses
|
||||
}
|
||||
|
||||
// CheckDependencies checks dependencies are installed on target servers.
|
||||
func CheckDependencies() {
|
||||
timeoutSec := 5 * 60
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
return o.checkDependencies()
|
||||
}, timeoutSec)
|
||||
return
|
||||
}
|
||||
|
||||
// CheckIfSudoNoPasswd checks whether vuls can sudo with nopassword via SSH
|
||||
func CheckIfSudoNoPasswd() {
|
||||
timeoutSec := 15
|
||||
timeoutSec := 5 * 60
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
return o.checkIfSudoNoPasswd()
|
||||
}, timeoutSec)
|
||||
@@ -380,117 +382,12 @@ func detectPlatforms() {
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare installs requred packages to scan vulnerabilities.
|
||||
func Prepare() error {
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
if err := o.checkDependencies(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
util.Log.Info("The following servers need to install dependencies")
|
||||
for _, s := range targets {
|
||||
for _, d := range s.getLackDependencies() {
|
||||
util.Log.Infof(" - %s on %s", d, s.getServerInfo().GetServerName())
|
||||
}
|
||||
}
|
||||
|
||||
if !config.Conf.AssumeYes {
|
||||
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 err
|
||||
}
|
||||
switch strings.TrimSpace(text) {
|
||||
case "", "N", "n":
|
||||
return nil
|
||||
case "y", "Y":
|
||||
goto yes
|
||||
default:
|
||||
util.Log.Info("Please enter y or N")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yes:
|
||||
servers = targets
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
if err := o.install(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
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")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Scan scan
|
||||
func Scan() error {
|
||||
if len(servers) == 0 {
|
||||
return fmt.Errorf("No server defined. Check the configuration")
|
||||
}
|
||||
|
||||
util.Log.Info("Check required packages for scanning...")
|
||||
checkRequiredPackagesInstalled()
|
||||
|
||||
if err := setupChangelogCache(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -530,14 +427,6 @@ func setupChangelogCache() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkRequiredPackagesInstalled() []error {
|
||||
timeoutSec := 30 * 60
|
||||
parallelExec(func(o osTypeInterface) error {
|
||||
return o.checkRequiredPackagesInstalled()
|
||||
}, timeoutSec)
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanVulns(jsonDir string, scannedAt time.Time) error {
|
||||
var results models.ScanResults
|
||||
timeoutSec := 120 * 60
|
||||
|
||||
@@ -30,14 +30,6 @@ 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