2016-01-12 13:01:04 -05:00
|
|
|
// Package aaparser is a convenience package interacting with `apparmor_parser`.
|
2015-11-23 18:41:18 -05:00
|
|
|
package aaparser
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os/exec"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2016-01-12 13:01:04 -05:00
|
|
|
const (
|
|
|
|
binary = "apparmor_parser"
|
|
|
|
)
|
|
|
|
|
|
|
|
// GetVersion returns the major and minor version of apparmor_parser.
|
2016-02-14 02:04:16 -05:00
|
|
|
func GetVersion() (int, error) {
|
2016-01-12 13:01:04 -05:00
|
|
|
output, err := cmd("", "--version")
|
|
|
|
if err != nil {
|
2016-02-14 02:04:16 -05:00
|
|
|
return -1, err
|
2016-01-12 13:01:04 -05:00
|
|
|
}
|
|
|
|
|
2016-02-14 02:04:16 -05:00
|
|
|
return parseVersion(output)
|
2016-01-12 13:01:04 -05:00
|
|
|
}
|
2015-11-23 18:41:18 -05:00
|
|
|
|
2017-05-17 10:02:00 -04:00
|
|
|
// LoadProfile runs `apparmor_parser -Kr` on a specified apparmor profile to
|
|
|
|
// replace the profile. The `-K` is necessary to make sure that apparmor_parser
|
|
|
|
// doesn't try to write to a read-only filesystem.
|
2016-01-12 13:01:04 -05:00
|
|
|
func LoadProfile(profilePath string) error {
|
2017-05-17 10:02:00 -04:00
|
|
|
_, err := cmd("", "-Kr", profilePath)
|
2016-12-13 15:10:11 -05:00
|
|
|
return err
|
2016-01-12 13:01:04 -05:00
|
|
|
}
|
2015-11-23 18:41:18 -05:00
|
|
|
|
2016-01-12 13:01:04 -05:00
|
|
|
// cmd runs `apparmor_parser` with the passed arguments.
|
|
|
|
func cmd(dir string, arg ...string) (string, error) {
|
|
|
|
c := exec.Command(binary, arg...)
|
|
|
|
c.Dir = dir
|
|
|
|
|
|
|
|
output, err := c.CombinedOutput()
|
|
|
|
if err != nil {
|
2016-12-13 01:25:57 -05:00
|
|
|
return "", fmt.Errorf("running `%s %s` failed with output: %s\nerror: %v", c.Path, strings.Join(c.Args, " "), output, err)
|
2016-01-12 13:01:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return string(output), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// parseVersion takes the output from `apparmor_parser --version` and returns
|
2016-02-14 02:04:16 -05:00
|
|
|
// a representation of the {major, minor, patch} version as a single number of
|
|
|
|
// the form MMmmPPP {major, minor, patch}.
|
|
|
|
func parseVersion(output string) (int, error) {
|
2015-11-23 18:41:18 -05:00
|
|
|
// output is in the form of the following:
|
|
|
|
// AppArmor parser version 2.9.1
|
|
|
|
// Copyright (C) 1999-2008 Novell Inc.
|
|
|
|
// Copyright 2009-2012 Canonical Ltd.
|
2016-02-14 02:04:16 -05:00
|
|
|
|
2016-01-12 13:01:04 -05:00
|
|
|
lines := strings.SplitN(output, "\n", 2)
|
2015-11-23 18:41:18 -05:00
|
|
|
words := strings.Split(lines[0], " ")
|
|
|
|
version := words[len(words)-1]
|
2016-01-12 13:01:04 -05:00
|
|
|
|
2015-11-23 18:41:18 -05:00
|
|
|
// split by major minor version
|
|
|
|
v := strings.Split(version, ".")
|
2016-02-14 02:04:16 -05:00
|
|
|
if len(v) == 0 || len(v) > 3 {
|
|
|
|
return -1, fmt.Errorf("parsing version failed for output: `%s`", output)
|
2015-11-23 18:41:18 -05:00
|
|
|
}
|
|
|
|
|
2016-02-14 02:04:16 -05:00
|
|
|
// Default the versions to 0.
|
|
|
|
var majorVersion, minorVersion, patchLevel int
|
|
|
|
|
2015-11-23 18:41:18 -05:00
|
|
|
majorVersion, err := strconv.Atoi(v[0])
|
|
|
|
if err != nil {
|
2016-02-14 02:04:16 -05:00
|
|
|
return -1, err
|
2015-11-23 18:41:18 -05:00
|
|
|
}
|
2016-02-14 02:04:16 -05:00
|
|
|
|
|
|
|
if len(v) > 1 {
|
|
|
|
minorVersion, err = strconv.Atoi(v[1])
|
|
|
|
if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(v) > 2 {
|
|
|
|
patchLevel, err = strconv.Atoi(v[2])
|
|
|
|
if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
2015-11-23 18:41:18 -05:00
|
|
|
}
|
|
|
|
|
2016-02-14 02:04:16 -05:00
|
|
|
// major*10^5 + minor*10^3 + patch*10^0
|
|
|
|
numericVersion := majorVersion*1e5 + minorVersion*1e3 + patchLevel
|
|
|
|
return numericVersion, nil
|
2015-11-23 18:41:18 -05:00
|
|
|
}
|