118 lines
2.8 KiB
Go
118 lines
2.8 KiB
Go
package apparmor
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"regexp"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
"github.com/godbus/dbus/v5/introspect"
|
|
"github.com/godbus/dbus/v5/prop"
|
|
|
|
logging "github.com/home-assistant/os-agent/utils/log"
|
|
)
|
|
|
|
const (
|
|
objectPath = "/io/hass/os/AppArmor"
|
|
ifaceName = "io.hass.os.AppArmor"
|
|
appArmorParserCmd = "apparmor_parser"
|
|
)
|
|
|
|
type apparmor struct {
|
|
conn *dbus.Conn
|
|
props *prop.Properties
|
|
}
|
|
|
|
func getAppArmorVersion() string {
|
|
cmd := exec.Command(appArmorParserCmd, "--version")
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
logging.Warning.Print(err)
|
|
return string("")
|
|
}
|
|
|
|
re := regexp.MustCompile("version ([0-9.]*)")
|
|
found := re.FindSubmatch(out)
|
|
if len(found) < 1 {
|
|
logging.Error.Fatalln("Can't read version from parser!")
|
|
}
|
|
|
|
return string(found[1])
|
|
}
|
|
|
|
func (d apparmor) LoadProfile(profilePath string, cachePath string) (bool, *dbus.Error) {
|
|
logging.Info.Printf("Load AppArmor profile '%s'.", profilePath)
|
|
|
|
cmd := exec.Command(appArmorParserCmd, "--replace", "--write-cache", "--cache-loc", cachePath, profilePath)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return false, dbus.MakeFailedError(fmt.Errorf("Can't load profile '%s': %w", profilePath, err))
|
|
}
|
|
|
|
logging.Info.Printf("Load profile '%s': %s", profilePath, out)
|
|
return true, nil
|
|
}
|
|
|
|
func (d apparmor) UnloadProfile(profilePath string, cachePath string) (bool, *dbus.Error) {
|
|
logging.Info.Printf("Unload AppArmor profile '%s'.", profilePath)
|
|
|
|
cmd := exec.Command(appArmorParserCmd, "--remove", "--write-cache", "--cache-loc", cachePath, profilePath)
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return false, dbus.MakeFailedError(fmt.Errorf("Can't unload profile '%s': %w", profilePath, err))
|
|
}
|
|
|
|
logging.Info.Printf("Unload profile '%s': %s", profilePath, out)
|
|
return true, nil
|
|
}
|
|
|
|
func InitializeDBus(conn *dbus.Conn) {
|
|
d := apparmor{
|
|
conn: conn,
|
|
}
|
|
|
|
propsSpec := map[string]map[string]*prop.Prop{
|
|
ifaceName: {
|
|
"ParserVersion": {
|
|
Value: getAppArmorVersion(),
|
|
Writable: false,
|
|
Emit: prop.EmitInvalidates,
|
|
Callback: nil,
|
|
},
|
|
},
|
|
}
|
|
|
|
props, err := prop.Export(conn, objectPath, propsSpec)
|
|
if err != nil {
|
|
logging.Critical.Panic(err)
|
|
}
|
|
d.props = props
|
|
|
|
err = conn.Export(d, objectPath, ifaceName)
|
|
if err != nil {
|
|
logging.Critical.Panic(err)
|
|
}
|
|
|
|
node := &introspect.Node{
|
|
Name: objectPath,
|
|
Interfaces: []introspect.Interface{
|
|
introspect.IntrospectData,
|
|
prop.IntrospectData,
|
|
{
|
|
Name: ifaceName,
|
|
Methods: introspect.Methods(d),
|
|
Properties: props.Introspection(ifaceName),
|
|
},
|
|
},
|
|
}
|
|
|
|
err = conn.Export(introspect.NewIntrospectable(node), objectPath, "org.freedesktop.DBus.Introspectable")
|
|
if err != nil {
|
|
logging.Critical.Panic(err)
|
|
}
|
|
|
|
logging.Info.Printf("Exposing object %s with interface %s ...", objectPath, ifaceName)
|
|
}
|