// apparmor.d - Full set of apparmor profiles // Copyright (C) 2023-2024 Alexandre Pujol // SPDX-License-Identifier: GPL-2.0-only package cli import ( "flag" "fmt" "strings" "github.com/roddhjav/apparmor.d/pkg/logging" "github.com/roddhjav/apparmor.d/pkg/paths" "github.com/roddhjav/apparmor.d/pkg/prebuild" "github.com/roddhjav/apparmor.d/pkg/prebuild/builder" "github.com/roddhjav/apparmor.d/pkg/prebuild/directive" "github.com/roddhjav/apparmor.d/pkg/prebuild/prepare" ) const ( nilABI uint = 0 usage = `aa-prebuild [-h] [--complain | --enforce] [--full] [--abi 3|4] Prebuild apparmor.d profiles for a given distribution and apply internal built-in directives. Options: -h, --help Show this help message and exit. -c, --complain Set complain flag on all profiles. -e, --enforce Set enforce flag on all profiles. -a, --abi ABI Target apparmor ABI. -f, --full Set AppArmor for full system policy. -F, --file Only prebuild a given file. ` ) var ( help bool complain bool enforce bool full bool abi uint file string ) func init() { flag.BoolVar(&help, "h", false, "Show this help message and exit.") flag.BoolVar(&help, "help", false, "Show this help message and exit.") flag.BoolVar(&full, "f", false, "Set AppArmor for full system policy.") flag.BoolVar(&full, "full", false, "Set AppArmor for full system policy.") flag.BoolVar(&complain, "c", false, "Set complain flag on all profiles.") flag.BoolVar(&complain, "complain", false, "Set complain flag on all profiles.") flag.BoolVar(&enforce, "e", false, "Set enforce flag on all profiles.") flag.BoolVar(&enforce, "enforce", false, "Set enforce flag on all profiles.") flag.UintVar(&abi, "a", nilABI, "Target apparmor ABI.") flag.UintVar(&abi, "abi", nilABI, "Target apparmor ABI.") flag.StringVar(&file, "F", "", "Only prebuild a given file.") flag.StringVar(&file, "file", "", "Only prebuild a given file.") } func Prebuild() { flag.Usage = func() { fmt.Printf("%s\n%s\n%s\n%s", usage, prebuild.Help("Prepare", prepare.Tasks), prebuild.Help("Build", builder.Builders), directive.Usage(), ) } flag.Parse() if help { flag.Usage() return } if full && paths.New("apparmor.d/groups/_full").Exist() { prepare.Register("fsp") builder.Register("fsp") } else if prebuild.SystemdDir.Exist() { prepare.Register("systemd-early") } if complain { builder.Register("complain") } else if enforce { builder.Register("enforce") } if abi != nilABI { prebuild.ABI = abi } switch prebuild.ABI { case 3: builder.Register("abi3") // Convert all profiles from abi 4.0 to abi 3.0 case 4: // builder.Register("attach") // Re-attach disconnect path default: logging.Fatal("Invalid ABI version: %d", prebuild.ABI) } if file != "" { sync, _ := prepare.Tasks["synchronise"].(*prepare.Synchronise) sync.Path = file overwrite, _ := prepare.Tasks["overwrite"].(*prepare.Overwrite) overwrite.OneFile = true } logging.Step("Building apparmor.d profiles for %s on ABI%d.", prebuild.Distribution, prebuild.ABI) if err := Prepare(); err != nil { logging.Fatal("%s", err.Error()) } if err := Build(); err != nil { logging.Fatal("%s", err.Error()) } } func Prepare() error { for _, task := range prepare.Prepares { msg, err := task.Apply() if err != nil { return err } if file != "" && task.Name() == "setflags" { continue } logging.Success("%s", task.Message()) logging.Indent = " " for _, line := range msg { if strings.Contains(line, "not found") { logging.Warning("%s", line) } else { logging.Bullet("%s", line) } } logging.Indent = "" } return nil } func Build() error { files, _ := prebuild.RootApparmord.ReadDirRecursiveFiltered(nil, paths.FilterOutDirectories()) for _, file := range files { if !file.Exist() { continue } profile, err := file.ReadFileAsString() if err != nil { return err } profile, err = builder.Run(file, profile) if err != nil { return err } profile, err = directive.Run(file, profile) if err != nil { return err } if err := file.WriteFile([]byte(profile)); err != nil { return err } } logging.Success("Build tasks:") logging.Indent = " " for _, task := range builder.Builds { logging.Bullet("%s", task.Message()) } logging.Indent = "" logging.Success("Directives processed:") logging.Indent = " " for _, dir := range directive.Directives { logging.Bullet("%s%s", directive.Keyword, dir.Name()) } logging.Indent = "" return nil }