apparmor.d/pkg/logs/loggers.go

125 lines
2.9 KiB
Go
Raw Normal View History

// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2024 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package logs
import (
2023-09-24 20:50:15 +02:00
"bufio"
"bytes"
"encoding/json"
2023-09-24 20:50:15 +02:00
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
2023-09-24 20:50:15 +02:00
"regexp"
"strings"
2023-09-24 20:50:15 +02:00
"github.com/roddhjav/apparmor.d/pkg/util"
)
// LogFiles is the list of default path to query
var LogFiles = []string{
"/var/log/audit/audit.log",
"/var/log/syslog",
}
// SystemdLog is a simplified systemd json log representation.
type systemdLog struct {
Message string `json:"MESSAGE"`
}
// GetApparmorLogs return a list of cleaned apparmor logs from a file
func GetApparmorLogs(file io.Reader, profile string) []string {
2024-04-28 13:06:40 +02:00
var logs []string
isAppArmorLog := isAppArmorLogTemplate.Copy()
if profile != "" {
exp := `apparmor=("DENIED"|"ALLOWED"|"AUDIT")`
exp = fmt.Sprintf(exp+`.* (profile="%s.*"|label="%s.*")`, profile, profile)
isAppArmorLog = regexp.MustCompile(exp)
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if isAppArmorLog.MatchString(line) {
2024-04-28 13:06:40 +02:00
logs = append(logs,
regCleanLogs.Replace(util.DecodeHexInString(line)),
)
}
}
return util.RemoveDuplicate(logs)
}
// GetAuditLogs return a reader with the logs entries from Auditd
func GetAuditLogs(path string) (io.Reader, error) {
file, err := os.Open(filepath.Clean(path))
if err != nil {
2024-04-28 13:06:40 +02:00
return nil, err
}
2024-04-28 13:06:40 +02:00
return file, nil
}
// GetJournalctlLogs return a reader with the logs entries from Systemd
func GetJournalctlLogs(path string, useFile bool) (io.Reader, error) {
var logs []systemdLog
var stdout bytes.Buffer
2024-04-28 13:06:40 +02:00
var scanner *bufio.Scanner
if useFile {
2024-04-28 13:06:40 +02:00
file, err := os.Open(filepath.Clean(path))
if err != nil {
return nil, err
}
2024-04-28 13:06:40 +02:00
scanner = bufio.NewScanner(file)
} else {
// journalctl -b -o json --output-fields=MESSAGE > systemd.log
cmd := exec.Command("journalctl", "--boot", "--output=json", "--output-fields=MESSAGE")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return nil, err
}
2024-04-28 13:06:40 +02:00
scanner = bufio.NewScanner(&stdout)
}
2024-04-28 13:06:40 +02:00
var jctlRaw []string
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, "apparmor") {
jctlRaw = append(jctlRaw, line)
}
}
2024-04-28 13:06:40 +02:00
jctlStr := "[" + strings.Join(jctlRaw, ",\n") + "]"
if err := json.Unmarshal([]byte(jctlStr), &logs); err != nil {
return nil, err
}
2024-04-28 13:06:40 +02:00
var res strings.Builder
for _, log := range logs {
2024-04-28 13:06:40 +02:00
res.WriteString(log.Message + "\n")
}
2024-04-28 13:06:40 +02:00
return strings.NewReader(res.String()), nil
}
2023-09-01 20:26:52 +02:00
// SelectLogFile return the path of the available log file to parse (audit, syslog, .1, .2)
func SelectLogFile(path string) string {
info, err := os.Stat(filepath.Clean(path))
if err == nil && !info.IsDir() {
return path
}
for _, logfile := range LogFiles {
if _, err := os.Stat(logfile); err == nil {
oldLogfile := filepath.Clean(logfile + "." + path)
if _, err := os.Stat(oldLogfile); err == nil {
return oldLogfile
} else {
return logfile
}
}
}
return ""
}