aaparser.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // Package aaparser is a convenience package interacting with `apparmor_parser`.
  2. package aaparser
  3. import (
  4. "fmt"
  5. "os/exec"
  6. "strconv"
  7. "strings"
  8. )
  9. const (
  10. binary = "apparmor_parser"
  11. )
  12. // GetVersion returns the major and minor version of apparmor_parser.
  13. func GetVersion() (int, error) {
  14. output, err := cmd("", "--version")
  15. if err != nil {
  16. return -1, err
  17. }
  18. return parseVersion(output)
  19. }
  20. // LoadProfile runs `apparmor_parser -Kr` on a specified apparmor profile to
  21. // replace the profile. The `-K` is necessary to make sure that apparmor_parser
  22. // doesn't try to write to a read-only filesystem.
  23. func LoadProfile(profilePath string) error {
  24. _, err := cmd("", "-Kr", profilePath)
  25. return err
  26. }
  27. // cmd runs `apparmor_parser` with the passed arguments.
  28. func cmd(dir string, arg ...string) (string, error) {
  29. c := exec.Command(binary, arg...)
  30. c.Dir = dir
  31. output, err := c.CombinedOutput()
  32. if err != nil {
  33. return "", fmt.Errorf("running `%s %s` failed with output: %s\nerror: %v", c.Path, strings.Join(c.Args, " "), output, err)
  34. }
  35. return string(output), nil
  36. }
  37. // parseVersion takes the output from `apparmor_parser --version` and returns
  38. // a representation of the {major, minor, patch} version as a single number of
  39. // the form MMmmPPP {major, minor, patch}.
  40. func parseVersion(output string) (int, error) {
  41. // output is in the form of the following:
  42. // AppArmor parser version 2.9.1
  43. // Copyright (C) 1999-2008 Novell Inc.
  44. // Copyright 2009-2012 Canonical Ltd.
  45. lines := strings.SplitN(output, "\n", 2)
  46. words := strings.Split(lines[0], " ")
  47. version := words[len(words)-1]
  48. // split by major minor version
  49. v := strings.Split(version, ".")
  50. if len(v) == 0 || len(v) > 3 {
  51. return -1, fmt.Errorf("parsing version failed for output: `%s`", output)
  52. }
  53. // Default the versions to 0.
  54. var majorVersion, minorVersion, patchLevel int
  55. majorVersion, err := strconv.Atoi(v[0])
  56. if err != nil {
  57. return -1, err
  58. }
  59. if len(v) > 1 {
  60. minorVersion, err = strconv.Atoi(v[1])
  61. if err != nil {
  62. return -1, err
  63. }
  64. }
  65. if len(v) > 2 {
  66. patchLevel, err = strconv.Atoi(v[2])
  67. if err != nil {
  68. return -1, err
  69. }
  70. }
  71. // major*10^5 + minor*10^3 + patch*10^0
  72. numericVersion := majorVersion*1e5 + minorVersion*1e3 + patchLevel
  73. return numericVersion, nil
  74. }