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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
package main
import (
"encoding/json"
"errors"
"flag"
"fmt"
"io/fs"
"os"
"strconv"
"syscall"
"git.ophivana.moe/cat/fortify/dbus"
"git.ophivana.moe/cat/fortify/internal/acl"
"git.ophivana.moe/cat/fortify/internal/app"
"git.ophivana.moe/cat/fortify/internal/state"
"git.ophivana.moe/cat/fortify/internal/system"
)
var (
Version = "impure"
a *app.App
dbusSession *dbus.Config
dbusSystem *dbus.Config
)
func tryVersion() {
if printVersion {
fmt.Println(Version)
os.Exit(0)
}
}
func main() {
flag.Parse()
// launcher payload early exit
app.Early(printVersion)
// version/license command early exit
tryVersion()
tryLicense()
system.Retrieve(flagVerbose)
a = app.New(userName, flag.Args())
state.Set(*a.User, a.Command(), a.UID())
// parse D-Bus config file if applicable
if mustDBus {
if dbusConfigSession == "builtin" {
dbusSession = dbus.NewConfig(dbusID, true, mpris)
} else {
if f, err := os.Open(dbusConfigSession); err != nil {
state.Fatal("Error opening D-Bus proxy config file:", err)
} else {
if err = json.NewDecoder(f).Decode(&dbusSession); err != nil {
state.Fatal("Error parsing D-Bus proxy config file:", err)
}
}
}
// system bus proxy is optional
if dbusConfigSystem != "nil" {
if f, err := os.Open(dbusConfigSystem); err != nil {
state.Fatal("Error opening D-Bus proxy config file:", err)
} else {
if err = json.NewDecoder(f).Decode(&dbusSystem); err != nil {
state.Fatal("Error parsing D-Bus proxy config file:", err)
}
}
}
}
// ensure RunDir (e.g. `/run/user/%d/fortify`)
if err := os.Mkdir(system.V.RunDir, 0700); err != nil && !errors.Is(err, fs.ErrExist) {
state.Fatal("Error creating runtime directory:", err)
}
// state query command early exit
state.Early()
// ensure Share (e.g. `/tmp/fortify.%d`)
// acl is unnecessary as this directory is world executable
if err := os.Mkdir(system.V.Share, 0701); err != nil && !errors.Is(err, fs.ErrExist) {
state.Fatal("Error creating shared directory:", err)
}
// warn about target user home directory ownership
if stat, err := os.Stat(a.HomeDir); err != nil {
if system.V.Verbose {
switch {
case errors.Is(err, fs.ErrPermission):
fmt.Printf("User %s home directory %s is not accessible", a.Username, a.HomeDir)
case errors.Is(err, fs.ErrNotExist):
fmt.Printf("User %s home directory %s does not exist", a.Username, a.HomeDir)
default:
fmt.Printf("Error stat user %s home directory %s: %s", a.Username, a.HomeDir, err)
}
}
return
} else {
// FreeBSD: not cross-platform
if u := strconv.Itoa(int(stat.Sys().(*syscall.Stat_t).Uid)); u != a.Uid {
fmt.Printf("User %s home directory %s has incorrect ownership (expected UID %s, found %s)", a.Username, a.HomeDir, a.Uid, u)
}
}
// ensure runtime directory ACL (e.g. `/run/user/%d`)
if s, err := os.Stat(system.V.Runtime); err != nil {
if errors.Is(err, fs.ErrNotExist) {
state.Fatal("Runtime directory does not exist")
}
state.Fatal("Error accessing runtime directory:", err)
} else if !s.IsDir() {
state.Fatal(fmt.Sprintf("Path '%s' is not a directory", system.V.Runtime))
} else {
if err = acl.UpdatePerm(system.V.Runtime, a.UID(), acl.Execute); err != nil {
state.Fatal("Error preparing runtime dir:", err)
} else {
state.RegisterRevertPath(system.V.Runtime)
}
if system.V.Verbose {
fmt.Printf("Runtime data dir '%s' configured\n", system.V.Runtime)
}
}
if mustWayland {
a.ShareWayland()
}
if mustX {
a.ShareX()
}
if mustDBus {
a.ShareDBus(dbusSession, dbusSystem, dbusVerbose)
}
if mustPulse {
a.SharePulse()
}
a.Run()
}
|