Add untested plugin support

This commit is contained in:
Sasha Koshka 2024-12-10 13:18:54 -05:00
parent 9a6607494f
commit 209270a179
2 changed files with 58 additions and 4 deletions

View File

@ -5,7 +5,9 @@ import "io"
import "fmt"
import "time"
import "io/fs"
import "plugin"
import "errors"
import "syscall"
import "context"
import "path/filepath"
import "html/template"
@ -103,6 +105,55 @@ func (this *Environment) Unload (name string) {
delete(documents, name)
}
// LoadProviderPlugin loads a plugin given its file path. The file must:
//
// - Be a shared library
// - Be built with go -buildmode=plugin
// - Be built with the same version of Go
// - Be built with the same version of STEP
// - Be owned by root
//
// Plugins cannot be unloaded from the current program once they are loaded.
// Sorgy :( its Go's fault.
func (this *Environment) LoadProviderPlugin (name string) (Provider, error) {
return this.loadProviderPlugin(name, true)
}
// LoadProviderPluginUnsafe is like LoadProviderPlugin, but does not check to
// see that the file is owned by root, thereby making it easier to run a random
// plugin you just compiled. This should not be used otherwise.
func (this *Environment) LoadProviderPluginUnsafe (name string) (Provider, error) {
return this.loadProviderPlugin(name, false)
}
func (this *Environment) loadProviderPlugin (name string, checkRoot bool) (Provider, error) {
plugin, err := this.loadPlugin(name, checkRoot)
if err != nil { return nil, err }
providerSymbol, err := plugin.Lookup("Provider")
if err != nil { return nil, err }
providerFactory, ok := providerSymbol.(func () Provider)
if !ok { return nil, ErrPluginBadSymbol }
provider := providerFactory()
this.Providers = append(this.Providers, provider)
return provider, nil
}
func (this *Environment) loadPlugin (name string, checkRoot bool) (*plugin.Plugin, error) {
name = filepath.Clean(name)
if checkRoot {
info, err := os.Stat(name)
if err != nil { return nil, err }
if info, ok := info.Sys().(*syscall.Stat_t); ok {
if info.Uid != 0 {
return nil, ErrPluginNotOwnedByRoot
}
} else {
return nil, ErrInsufficientSystem
}
}
return plugin.Open(name)
}
func (this *Environment) parse (name string, modTime time.Time, input io.Reader) (*Document, error) {
documents, done := this.documents.Borrow()
defer done()

View File

@ -2,10 +2,13 @@ package step
// Error enumerates errors common to this package.
type Error string; const (
ErrCircularInheritance Error = "circular inheritance"
ErrMetaMalformed Error = "metadata is malformed"
ErrMetaNeverClosed Error = "metadata is never closed"
ErrTypeMismatch Error = "type mismatch"
ErrCircularInheritance Error = "circular inheritance"
ErrMetaMalformed Error = "metadata is malformed"
ErrMetaNeverClosed Error = "metadata is never closed"
ErrTypeMismatch Error = "type mismatch"
ErrPluginBadSymbol Error = "plugin has an incorrect symbol"
ErrPluginNotOwnedByRoot Error = "plugin is not owned by the root user"
ErrInsufficientSystem Error = "the system cannot perform this action"
)
// Error fulfills the error interface.