Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

main: help subcommand should work without root. #31

Merged
merged 5 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions bundles.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,14 @@ type Bundles map[string]*Bundle

var BundleDBPath = filepath.Join(DatabasePath, "bundles.db")

func ReadBundleDatabase(dbpath string) Bundles {
bundles := make(Bundles)
os.MkdirAll(DatabasePath, os.ModePerm)
if _, err := os.Stat(BundleDBPath); os.IsNotExist(err) {
file, err := os.Create(BundleDBPath)
if err != nil {
log.Fatal(err)
}
file.Close()
}
f, err := ioutil.ReadFile(dbpath)
func ReadBundleDatabase(dbpath string) (Bundles, error) {
f, err := ReadOrCreateFile(dbpath)
if err != nil {
log.Fatal(err)
return nil, err
}
bundles := make(Bundles)
json.Unmarshal(f, &bundles)
return bundles
return bundles, nil
}

func WriteBundleDatabase(dbpath string, bundles Bundles) {
Expand Down
44 changes: 25 additions & 19 deletions cmd/sbctl/main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package main

import (
"fmt"
"log"
"os"
"path/filepath"
"strings"

"github.com/foxboron/sbctl"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -86,7 +84,10 @@ func signAllCmd() *cobra.Command {
outBundle = sbctl.GenerateAllBundles(true)
}

files := sbctl.ReadFileDatabase(sbctl.DBPath)
files, err := sbctl.ReadFileDatabase(sbctl.DBPath)
if err != nil {
log.Fatalln(err)
}
for _, entry := range files {

if sbctl.SignFile(sbctl.DBKey, sbctl.DBCert, entry.File, entry.OutputFile, entry.Checksum) != nil {
Expand Down Expand Up @@ -120,7 +121,10 @@ func removeFileCmd() *cobra.Command {
if len(args) < 1 {
log.Fatal("Need to specify file")
}
files := sbctl.ReadFileDatabase(sbctl.DBPath)
files, err := sbctl.ReadFileDatabase(sbctl.DBPath)
if err != nil {
log.Fatalln(err)
}
if _, ok := files[args[0]]; !ok {
log.Printf("File %s doesn't exist in database!\n", args[0])
os.Exit(1)
Expand All @@ -146,7 +150,9 @@ func verifyCmd() *cobra.Command {
Use: "verify",
Short: "Find and check if files in the ESP are signed or not",
Run: func(cmd *cobra.Command, args []string) {
sbctl.VerifyESP()
if err := sbctl.VerifyESP(); err != nil {
log.Fatalln(err)
}
},
}
}
Expand Down Expand Up @@ -194,6 +200,16 @@ func bundleCmd() *cobra.Command {
if err != nil {
log.Fatal(err)
}
// Fail early if user wants to save bundle but doesn't have permissions
var bundles sbctl.Bundles
if save {
// "err" needs to have been declared before this, otherwise it's necessary
// to use ":=", which shadows the "bundles" variable
bundles, err = sbctl.ReadBundleDatabase(sbctl.BundleDBPath)
if err != nil {
log.Fatalln(err)
}
}
bundle.Output = output
bundle.IntelMicrocode = intelucode
bundle.AMDMicrocode = amducode
Expand All @@ -206,7 +222,6 @@ func bundleCmd() *cobra.Command {
bundle.ESP = espPath
sbctl.CreateBundle(*bundle)
if save {
bundles := sbctl.ReadBundleDatabase(sbctl.BundleDBPath)
bundles[bundle.Output] = bundle
sbctl.WriteBundleDatabase(sbctl.BundleDBPath, bundles)
sbctl.FormatBundle(bundle.Output, bundle)
Expand Down Expand Up @@ -260,7 +275,10 @@ func removeBundleCmd() *cobra.Command {
if len(args) < 1 {
log.Fatal("Need to specify file")
}
bundles := sbctl.ReadBundleDatabase(sbctl.BundleDBPath)
bundles, err := sbctl.ReadBundleDatabase(sbctl.BundleDBPath)
if err != nil {
log.Fatalln(err)
}

if _, ok := bundles[args[0]]; !ok {
log.Printf("Bundle %s doesn't exist in database!\n", args[0])
Expand Down Expand Up @@ -306,18 +324,6 @@ func completionFishCmd() *cobra.Command {
}

func main() {
rootCmd.PersistentPreRun = func(c *cobra.Command, args []string) {
if strings.Contains(c.CommandPath(), "completion zsh") ||
strings.Contains(c.CommandPath(), "completion bash") ||
strings.Contains(c.CommandPath(), "completion fish") ||
strings.Contains(c.CommandPath(), "__complete") {
return
}
if os.Geteuid() != 0 {
fmt.Println("Needs to be executed as root")
os.Exit(1)
}
}
rootCmd.AddCommand(createKeysCmd())
rootCmd.AddCommand(enrollKeysCmd())
rootCmd.AddCommand(signCmd())
Expand Down
24 changes: 7 additions & 17 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"encoding/json"
"io/ioutil"
"log"
"os"
"path/filepath"
)

type SigningEntry struct {
Expand All @@ -16,24 +14,16 @@ type SigningEntry struct {

type SigningEntries map[string]*SigningEntry

var DBPath = filepath.Join(DatabasePath, "files.db")

func ReadFileDatabase(dbpath string) SigningEntries {
files := make(SigningEntries)
os.MkdirAll(DatabasePath, os.ModePerm)
if _, err := os.Stat(DBPath); os.IsNotExist(err) {
file, err := os.Create(DBPath)
if err != nil {
log.Fatal(err)
}
file.Close()
}
f, err := ioutil.ReadFile(dbpath)
func ReadFileDatabase(dbpath string) (SigningEntries, error) {
f, err := ReadOrCreateFile(dbpath)
if err != nil {
log.Fatal(err)
return nil, err
}

files := make(SigningEntries)
json.Unmarshal(f, &files)
return files

return files, nil
}

func WriteFileDatabase(dbpath string, files SigningEntries) {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ require (
github.com/foxboron/go-uefi v0.0.0-20210105211851-5faf8e43ee9b
github.com/google/uuid v1.1.1
github.com/spf13/cobra v1.0.0
golang.org/x/sys v0.0.0-20201109165425-215b40eba54c
)
2 changes: 1 addition & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
Expand Down Expand Up @@ -118,6 +117,7 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201109165425-215b40eba54c h1:+B+zPA6081G5cEb2triOIJpcvSW4AYzmIyWAqMn2JAc=
golang.org/x/sys v0.0.0-20201109165425-215b40eba54c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
9 changes: 9 additions & 0 deletions keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"strings"

"github.com/google/uuid"
"golang.org/x/sys/unix"
)

var RSAKeySize = 4096
Expand All @@ -30,6 +31,8 @@ var (
KEKCert = filepath.Join(KeysPath, "KEK", "KEK.pem")
DBKey = filepath.Join(KeysPath, "db", "db.key")
DBCert = filepath.Join(KeysPath, "db", "db.pem")

DBPath = filepath.Join(DatabasePath, "files.db")
)

func CreateKey(path, name string) []byte {
Expand Down Expand Up @@ -155,6 +158,12 @@ func SignFile(key, cert, file, output, checksum string) error {
return nil
}

// Let's also check if we can access the key
if err := unix.Access(key, unix.R_OK); err != nil {
err2.Printf("Couldn't access %s", key)
return err
}

msg2.Printf("Signing %s...", file)
args := fmt.Sprintf("--key %s --cert %s --output %s %s", key, cert, output, file)
_, err := exec.Command("sbsign", strings.Split(args, " ")...).Output()
Expand Down
8 changes: 6 additions & 2 deletions log.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var (
msg2 *log.Logger
warning *log.Logger
warning2 *log.Logger
err *log.Logger
err1 *log.Logger
err2 *log.Logger
)

Expand All @@ -31,6 +31,10 @@ var (
prefix = off
)

var (
rootMsg = "It might be necessary to run this tool as root"
)

func GetColor(args string) string {
out, _ := exec.Command("tput", strings.Split(args, " ")...).Output()
return string(bytes.TrimSuffix(out, []byte("\n")))
Expand All @@ -54,7 +58,7 @@ func init() {
warning2 = log.New(os.Stderr, warning2fmt, 0)

errfmt := fmt.Sprintf("%s%s%s==> ERROR:%s%s ", prefix, bold, red, off, bold)
err = log.New(os.Stderr, errfmt, 0)
err1 = log.New(os.Stderr, errfmt, 0)

err2fmt := fmt.Sprintf("%s%s%s -> ERROR:%s%s ", prefix, bold, red, off, bold)
err2 = log.New(os.Stderr, err2fmt, 0)
Expand Down
61 changes: 40 additions & 21 deletions sbctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,18 @@ func GetESP() string {
return ""
}

func VerifyESP() {
// Cache files we have looked at.
checked := make(map[string]bool)

func VerifyESP() error {
espPath := GetESP()
files := ReadFileDatabase(DBPath)
msg.Printf("Verifying file database and EFI images in %s...", espPath)
files, err := ReadFileDatabase(DBPath)
if err != nil {
warning.Printf("Couldn't read file database: %s", err)
msg.Printf("Verifying EFI images in %s...", espPath)
} else {
msg.Printf("Verifying file database and EFI images in %s...", espPath)
}

// Cache files we have looked at.
checked := make(map[string]bool)
for _, file := range files {
normalized := strings.Join(strings.Split(file.OutputFile, "/")[2:], "/")
checked[normalized] = true
Expand All @@ -62,7 +66,7 @@ func VerifyESP() {
}
}

err := filepath.Walk(espPath, func(path string, info os.FileInfo, err error) error {
err = filepath.Walk(espPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
Expand Down Expand Up @@ -99,6 +103,8 @@ func VerifyESP() {
if err != nil {
log.Println(err)
}

return nil
}

func Sign(file, output string, enroll bool) error {
Expand All @@ -118,7 +124,10 @@ func Sign(file, output string, enroll bool) error {

err = nil

files := ReadFileDatabase(DBPath)
files, err := ReadFileDatabase(DBPath)
if err != nil {
return err
}
if entry, ok := files[file]; ok {
err = SignFile(DBKey, DBCert, entry.File, entry.OutputFile, entry.Checksum)
// return early if signing fails
Expand Down Expand Up @@ -147,7 +156,11 @@ func Sign(file, output string, enroll bool) error {
}

func ListFiles() {
files := ReadFileDatabase(DBPath)
files, err := ReadFileDatabase(DBPath)
if err != nil {
err2.Printf("Couldn't open database: %s", DBPath)
return
}
for path, s := range files {
msg.Printf("File: %s", path)
if path != s.OutputFile {
Expand Down Expand Up @@ -189,17 +202,17 @@ func CreateKeys() {
func SyncKeys() {
synced := SBKeySync(KeysPath)
if !synced {
err.Println("Couldn't sync keys")
err1.Println("Couldn't sync keys")
os.Exit(1)
} else {
msg.Println("Synced keys!")
}
}

func CombineFiles(microcode, initramfs string) (*os.File, error) {
tmpFile, e := ioutil.TempFile("/var/tmp", "initramfs-")
if e != nil {
err.Println("Cannot create temporary file", e)
tmpFile, err := ioutil.TempFile("/var/tmp", "initramfs-")
if err != nil {
err1.Println("Cannot create temporary file", err)
}

one, _ := os.Open(microcode)
Expand All @@ -208,13 +221,13 @@ func CombineFiles(microcode, initramfs string) (*os.File, error) {
two, _ := os.Open(initramfs)
defer two.Close()

_, e = io.Copy(tmpFile, one)
if e != nil {
_, err = io.Copy(tmpFile, one)
if err != nil {
return nil, PrintGenerateError(err2, "failed to append microcode file to output:", err)
}

_, e = io.Copy(tmpFile, two)
if e != nil {
_, err = io.Copy(tmpFile, two)
if err != nil {
return nil, PrintGenerateError(err2, "failed to append initramfs file to output:", err)
}

Expand Down Expand Up @@ -247,7 +260,10 @@ func CreateBundle(bundle Bundle) error {

func GenerateAllBundles(sign bool) error {
msg.Println("Generating EFI bundles....")
bundles := ReadBundleDatabase(BundleDBPath)
bundles, err := ReadBundleDatabase(BundleDBPath)
if err != nil {
return err
}
out_create := true
out_sign := true
for _, bundle := range bundles {
Expand All @@ -267,18 +283,21 @@ func GenerateAllBundles(sign bool) error {
}

if !out_create {
return PrintGenerateError(err, "Error generating EFI bundles")
return PrintGenerateError(err1, "Error generating EFI bundles")
}

if !out_sign {
return PrintGenerateError(err, "Error signing EFI bundles")
return PrintGenerateError(err1, "Error signing EFI bundles")
}

return nil
}

func ListBundles() {
bundles := ReadBundleDatabase(BundleDBPath)
bundles, err := ReadBundleDatabase(BundleDBPath)
if err != nil {
log.Fatalln(err)
}
for key, bundle := range bundles {
FormatBundle(key, bundle)
}
Expand Down
Loading