2021-11-09 23:41:12 +01:00
|
|
|
// aa-log - Review AppArmor generated messages
|
2024-02-07 00:16:21 +01:00
|
|
|
// Copyright (C) 2021-2024 Alexandre Pujol <alexandre@pujol.io>
|
2021-11-09 23:41:12 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2022-02-10 22:30:51 +01:00
|
|
|
"flag"
|
2021-11-09 23:41:12 +01:00
|
|
|
"fmt"
|
2022-05-02 18:14:42 +02:00
|
|
|
"io"
|
2021-11-09 23:41:12 +01:00
|
|
|
"os"
|
2024-04-28 01:04:42 +02:00
|
|
|
"slices"
|
2023-09-30 16:34:30 +02:00
|
|
|
"strings"
|
2023-04-17 00:33:07 +02:00
|
|
|
|
|
|
|
"github.com/roddhjav/apparmor.d/pkg/logs"
|
2021-11-09 23:41:12 +01:00
|
|
|
)
|
|
|
|
|
2023-10-10 21:44:50 +02:00
|
|
|
const usage = `aa-log [-h] [--systemd] [--file file] [--rules | --raw] [profile]
|
2023-02-19 18:53:49 +01:00
|
|
|
|
|
|
|
Review AppArmor generated messages in a colorful way. Supports logs from
|
|
|
|
auditd, systemd, syslog as well as dbus session events.
|
|
|
|
|
|
|
|
It can be given an optional profile name to filter the output with.
|
|
|
|
|
|
|
|
Default logs are read from '/var/log/audit/audit.log'. Other files in
|
|
|
|
'/var/log/audit/' can easily be checked: 'aa-log -f 1' parses 'audit.log.1'
|
|
|
|
|
|
|
|
Options:
|
|
|
|
-h, --help Show this help message and exit.
|
|
|
|
-f, --file FILE Set a logfile or a suffix to the default log file.
|
|
|
|
-s, --systemd Parse systemd logs from journalctl.
|
2023-08-18 00:14:11 +02:00
|
|
|
-r, --rules Convert the log into AppArmor rules.
|
2023-09-24 20:50:15 +02:00
|
|
|
-R, --raw Print the raw log without any formatting.
|
2023-02-19 18:53:49 +01:00
|
|
|
|
|
|
|
`
|
|
|
|
|
2022-02-10 22:30:51 +01:00
|
|
|
// Command line options
|
|
|
|
var (
|
2023-08-17 20:12:02 +02:00
|
|
|
help bool
|
2023-08-18 00:14:11 +02:00
|
|
|
rules bool
|
2023-08-17 20:12:02 +02:00
|
|
|
path string
|
|
|
|
systemd bool
|
2023-09-24 20:50:15 +02:00
|
|
|
raw bool
|
2022-02-10 22:30:51 +01:00
|
|
|
)
|
|
|
|
|
2023-09-01 20:26:52 +02:00
|
|
|
func aaLog(logger string, path string, profile string) error {
|
2022-10-06 22:11:35 +02:00
|
|
|
var err error
|
|
|
|
var file io.Reader
|
|
|
|
|
|
|
|
switch logger {
|
|
|
|
case "auditd":
|
2023-04-17 00:33:07 +02:00
|
|
|
file, err = logs.GetAuditLogs(path)
|
2022-10-06 22:11:35 +02:00
|
|
|
case "systemd":
|
2023-05-06 14:01:07 +02:00
|
|
|
file, err = logs.GetJournalctlLogs(path, !slices.Contains(logs.LogFiles, path))
|
2022-10-06 22:11:35 +02:00
|
|
|
default:
|
2022-10-16 13:11:07 +02:00
|
|
|
err = fmt.Errorf("Logger %s not supported.", logger)
|
2022-10-06 22:11:35 +02:00
|
|
|
}
|
2021-11-09 23:41:12 +01:00
|
|
|
if err != nil {
|
2021-12-12 13:35:08 +01:00
|
|
|
return err
|
2021-11-09 23:41:12 +01:00
|
|
|
}
|
2023-08-18 00:14:11 +02:00
|
|
|
|
2023-09-24 20:50:15 +02:00
|
|
|
if raw {
|
2024-03-05 19:29:44 +01:00
|
|
|
fmt.Print(strings.Join(logs.GetApparmorLogs(file, profile), "\n") + "\n")
|
2023-09-24 20:50:15 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-17 00:33:07 +02:00
|
|
|
aaLogs := logs.NewApparmorLogs(file, profile)
|
2023-08-18 00:14:11 +02:00
|
|
|
if rules {
|
|
|
|
profiles := aaLogs.ParseToProfiles()
|
|
|
|
for _, profile := range profiles {
|
2023-09-25 01:17:41 +02:00
|
|
|
profile.MergeRules()
|
2023-10-01 20:00:39 +02:00
|
|
|
profile.Sort()
|
|
|
|
profile.Format()
|
2023-08-18 00:14:11 +02:00
|
|
|
fmt.Print(profile.String() + "\n")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fmt.Print(aaLogs.String())
|
|
|
|
}
|
2022-08-19 20:05:46 +02:00
|
|
|
return nil
|
2021-12-12 13:35:08 +01:00
|
|
|
}
|
|
|
|
|
2022-02-10 22:30:51 +01:00
|
|
|
func init() {
|
|
|
|
flag.BoolVar(&help, "h", false, "Show this help message and exit.")
|
2023-02-19 18:53:49 +01:00
|
|
|
flag.BoolVar(&help, "help", false, "Show this help message and exit.")
|
2023-03-12 17:54:54 +01:00
|
|
|
flag.StringVar(&path, "f", "", "Set a logfile or a suffix to the default log file.")
|
|
|
|
flag.StringVar(&path, "file", "", "Set a logfile or a suffix to the default log file.")
|
2023-02-19 18:53:49 +01:00
|
|
|
flag.BoolVar(&systemd, "s", false, "Parse systemd logs from journalctl.")
|
|
|
|
flag.BoolVar(&systemd, "systemd", false, "Parse systemd logs from journalctl.")
|
2023-08-18 00:14:11 +02:00
|
|
|
flag.BoolVar(&rules, "r", false, "Convert the log into AppArmor rules.")
|
|
|
|
flag.BoolVar(&rules, "rules", false, "Convert the log into AppArmor rules.")
|
2023-09-24 20:50:15 +02:00
|
|
|
flag.BoolVar(&raw, "R", false, "Print the raw log without any formatting.")
|
|
|
|
flag.BoolVar(&raw, "raw", false, "Print the raw log without any formatting.")
|
2022-02-10 22:30:51 +01:00
|
|
|
}
|
|
|
|
|
2021-12-12 13:35:08 +01:00
|
|
|
func main() {
|
2023-02-19 18:53:49 +01:00
|
|
|
flag.Usage = func() { fmt.Print(usage) }
|
2022-02-10 22:30:51 +01:00
|
|
|
flag.Parse()
|
|
|
|
if help {
|
2023-02-19 18:53:49 +01:00
|
|
|
flag.Usage()
|
2022-02-10 22:30:51 +01:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
profile := ""
|
|
|
|
if len(flag.Args()) >= 1 {
|
|
|
|
profile = flag.Args()[0]
|
|
|
|
}
|
|
|
|
|
2022-10-06 22:11:35 +02:00
|
|
|
logger := "auditd"
|
|
|
|
if systemd {
|
|
|
|
logger = "systemd"
|
|
|
|
}
|
|
|
|
|
2023-09-01 20:26:52 +02:00
|
|
|
path = logs.SelectLogFile(path)
|
|
|
|
err := aaLog(logger, path, profile)
|
2021-12-12 13:35:08 +01:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
2021-11-09 23:41:12 +01:00
|
|
|
}
|