2024-07-09 15:39:40 +09:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-09-09 03:16:54 +09:00
|
|
|
"encoding/json"
|
2024-07-15 23:29:21 +09:00
|
|
|
"errors"
|
2024-07-09 15:39:40 +09:00
|
|
|
"flag"
|
2024-07-15 23:29:21 +09:00
|
|
|
"fmt"
|
|
|
|
"io/fs"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"syscall"
|
2024-09-04 01:20:12 +09:00
|
|
|
|
2024-09-09 03:16:54 +09:00
|
|
|
"git.ophivana.moe/cat/fortify/dbus"
|
2024-09-04 01:20:12 +09:00
|
|
|
"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"
|
2024-07-09 15:39:40 +09:00
|
|
|
)
|
|
|
|
|
2024-09-04 01:20:12 +09:00
|
|
|
var (
|
|
|
|
Version = "impure"
|
2024-09-09 03:16:54 +09:00
|
|
|
|
|
|
|
a *app.App
|
|
|
|
c *dbus.Config
|
2024-09-04 01:20:12 +09:00
|
|
|
)
|
2024-07-09 15:39:40 +09:00
|
|
|
|
2024-07-16 22:07:40 +09:00
|
|
|
func tryVersion() {
|
|
|
|
if printVersion {
|
|
|
|
fmt.Println(Version)
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-09 15:39:40 +09:00
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
2024-07-15 23:29:21 +09:00
|
|
|
|
2024-09-04 01:20:12 +09:00
|
|
|
// launcher payload early exit
|
|
|
|
app.Early(printVersion)
|
2024-07-15 23:29:21 +09:00
|
|
|
|
2024-09-04 01:20:12 +09:00
|
|
|
// version/license command early exit
|
|
|
|
tryVersion()
|
|
|
|
tryLicense()
|
|
|
|
|
|
|
|
system.Retrieve(flagVerbose)
|
|
|
|
a = app.New(userName, flag.Args())
|
|
|
|
state.Set(*a.User, a.Command(), a.UID())
|
|
|
|
|
2024-09-09 03:16:54 +09:00
|
|
|
// parse D-Bus config file if applicable
|
|
|
|
if mustDBus {
|
|
|
|
if dbusConfig == "builtin" {
|
|
|
|
c = dbus.NewConfig(dbusID, true, mpris)
|
|
|
|
} else {
|
|
|
|
if f, err := os.Open(dbusConfig); err != nil {
|
|
|
|
state.Fatal("Error opening D-Bus proxy config file:", err)
|
|
|
|
} else {
|
|
|
|
if err = json.NewDecoder(f).Decode(&c); err != nil {
|
|
|
|
state.Fatal("Error parsing D-Bus proxy config file:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-04 01:20:12 +09:00
|
|
|
// 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)
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
|
|
|
|
2024-09-04 01:20:12 +09:00
|
|
|
// 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)
|
|
|
|
}
|
2024-07-16 14:19:43 +09:00
|
|
|
|
2024-09-04 01:20:12 +09:00
|
|
|
// warn about target user home directory ownership
|
|
|
|
if stat, err := os.Stat(a.HomeDir); err != nil {
|
|
|
|
if system.V.Verbose {
|
2024-07-15 23:29:21 +09:00
|
|
|
switch {
|
|
|
|
case errors.Is(err, fs.ErrPermission):
|
2024-09-04 01:20:12 +09:00
|
|
|
fmt.Printf("User %s home directory %s is not accessible", a.Username, a.HomeDir)
|
2024-07-15 23:29:21 +09:00
|
|
|
case errors.Is(err, fs.ErrNotExist):
|
2024-09-04 01:20:12 +09:00
|
|
|
fmt.Printf("User %s home directory %s does not exist", a.Username, a.HomeDir)
|
2024-07-15 23:29:21 +09:00
|
|
|
default:
|
2024-09-04 01:20:12 +09:00
|
|
|
fmt.Printf("Error stat user %s home directory %s: %s", a.Username, a.HomeDir, err)
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
// FreeBSD: not cross-platform
|
2024-09-04 01:20:12 +09:00
|
|
|
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)
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-04 01:20:12 +09:00
|
|
|
// ensure runtime directory ACL (e.g. `/run/user/%d`)
|
|
|
|
if s, err := os.Stat(system.V.Runtime); err != nil {
|
2024-07-15 23:29:21 +09:00
|
|
|
if errors.Is(err, fs.ErrNotExist) {
|
2024-09-04 01:20:12 +09:00
|
|
|
state.Fatal("Runtime directory does not exist")
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
2024-09-04 01:20:12 +09:00
|
|
|
state.Fatal("Error accessing runtime directory:", err)
|
2024-07-15 23:29:21 +09:00
|
|
|
} else if !s.IsDir() {
|
2024-09-04 01:20:12 +09:00
|
|
|
state.Fatal(fmt.Sprintf("Path '%s' is not a directory", system.V.Runtime))
|
2024-07-15 23:29:21 +09:00
|
|
|
} else {
|
2024-09-04 01:20:12 +09:00
|
|
|
if err = acl.UpdatePerm(system.V.Runtime, a.UID(), acl.Execute); err != nil {
|
|
|
|
state.Fatal("Error preparing runtime dir:", err)
|
2024-07-16 14:19:43 +09:00
|
|
|
} else {
|
2024-09-04 01:20:12 +09:00
|
|
|
state.RegisterRevertPath(system.V.Runtime)
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
2024-09-04 01:20:12 +09:00
|
|
|
if system.V.Verbose {
|
|
|
|
fmt.Printf("Runtime data dir '%s' configured\n", system.V.Runtime)
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-08 02:24:01 +09:00
|
|
|
if mustWayland {
|
|
|
|
a.ShareWayland()
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
|
|
|
|
2024-09-08 02:24:01 +09:00
|
|
|
if mustX {
|
|
|
|
a.ShareX()
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
|
|
|
|
2024-09-08 02:24:01 +09:00
|
|
|
if mustDBus {
|
2024-09-09 03:16:54 +09:00
|
|
|
a.ShareDBus(c)
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
|
|
|
|
2024-09-08 02:24:01 +09:00
|
|
|
if mustPulse {
|
|
|
|
a.SharePulse()
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|
|
|
|
|
2024-09-04 01:20:12 +09:00
|
|
|
a.Run()
|
2024-07-15 23:29:21 +09:00
|
|
|
}
|