aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/system.go
blob: 5f5e76bc412e288ff08a3b336b2b2833f773c510 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package internal

import (
	"io/fs"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strconv"
	"sync"

	"git.ophivana.moe/security/fortify/internal/fmsg"
)

// System provides safe access to operating system resources.
type System interface {
	// Geteuid provides [os.Geteuid].
	Geteuid() int
	// LookupEnv provides [os.LookupEnv].
	LookupEnv(key string) (string, bool)
	// TempDir provides [os.TempDir].
	TempDir() string
	// LookPath provides [exec.LookPath].
	LookPath(file string) (string, error)
	// Executable provides [os.Executable].
	Executable() (string, error)
	// Lookup provides [user.Lookup].
	Lookup(username string) (*user.User, error)
	// ReadDir provides [os.ReadDir].
	ReadDir(name string) ([]os.DirEntry, error)
	// Stat provides [os.Stat].
	Stat(name string) (fs.FileInfo, error)
	// Open provides [os.Open]
	Open(name string) (fs.File, error)
	// Exit provides [os.Exit].
	Exit(code int)

	// Paths returns a populated [Paths] struct.
	Paths() Paths
}

// Paths contains environment dependent paths used by fortify.
type Paths struct {
	// path to shared directory e.g. /tmp/fortify.%d
	SharePath string `json:"share_path"`
	// XDG_RUNTIME_DIR value e.g. /run/user/%d
	RuntimePath string `json:"runtime_path"`
	// application runtime directory e.g. /run/user/%d/fortify
	RunDirPath string `json:"run_dir_path"`
}

// CopyPaths is a generic implementation of [System.Paths].
func CopyPaths(os System, v *Paths) {
	v.SharePath = path.Join(os.TempDir(), "fortify."+strconv.Itoa(os.Geteuid()))

	fmsg.VPrintf("process share directory at %q", v.SharePath)

	if r, ok := os.LookupEnv(xdgRuntimeDir); !ok || r == "" || !path.IsAbs(r) {
		// fall back to path in share since fortify has no hard XDG dependency
		v.RunDirPath = path.Join(v.SharePath, "run")
		v.RuntimePath = path.Join(v.RunDirPath, "compat")
	} else {
		v.RuntimePath = r
		v.RunDirPath = path.Join(v.RuntimePath, "fortify")
	}

	fmsg.VPrintf("runtime directory at %q", v.RunDirPath)
}

// Std implements System using the standard library.
type Std struct {
	paths     Paths
	pathsOnce sync.Once
}

func (s *Std) Geteuid() int {
	return os.Geteuid()
}

func (s *Std) LookupEnv(key string) (string, bool) {
	return os.LookupEnv(key)
}

func (s *Std) TempDir() string {
	return os.TempDir()
}

func (s *Std) LookPath(file string) (string, error) {
	return exec.LookPath(file)
}

func (s *Std) Executable() (string, error) {
	return os.Executable()
}

func (s *Std) Lookup(username string) (*user.User, error) {
	return user.Lookup(username)
}

func (s *Std) ReadDir(name string) ([]os.DirEntry, error) {
	return os.ReadDir(name)
}

func (s *Std) Stat(name string) (fs.FileInfo, error) {
	return os.Stat(name)
}

func (s *Std) Open(name string) (fs.File, error) {
	return os.Open(name)
}
func (s *Std) Exit(code int) {
	os.Exit(code)
}

const xdgRuntimeDir = "XDG_RUNTIME_DIR"

func (s *Std) Paths() Paths {
	s.pathsOnce.Do(func() { CopyPaths(s, &s.paths) })
	return s.paths
}