diff options
| author | Ophestra Umiker <cat@ophivana.moe> | 2024-09-04 01:20:12 +0900 |
|---|---|---|
| committer | Ophestra Umiker <cat@ophivana.moe> | 2024-09-04 01:20:12 +0900 |
| commit | d8f76f3b2594db4687c0203c4f2be8d3e4ef7740 (patch) | |
| tree | b1d8bfb5250d71094e397f8afa87710de1f1ca2f /internal/state | |
| parent | 7e6eb82195c650bc34829e5cca2d2296e78c0707 (diff) | |
rename to fortify and restructure
More sandbox features will be added and this will no longer track ego's features and behaviour.
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'internal/state')
| -rw-r--r-- | internal/state/exit.go | 68 | ||||
| -rw-r--r-- | internal/state/register.go | 12 | ||||
| -rw-r--r-- | internal/state/track.go | 115 | ||||
| -rw-r--r-- | internal/state/value.go | 21 |
4 files changed, 216 insertions, 0 deletions
diff --git a/internal/state/exit.go b/internal/state/exit.go new file mode 100644 index 00000000..e0e2c04a --- /dev/null +++ b/internal/state/exit.go @@ -0,0 +1,68 @@ +package state + +import ( + "errors" + "fmt" + "io/fs" + "os" + + "git.ophivana.moe/cat/fortify/internal/acl" + "git.ophivana.moe/cat/fortify/internal/system" + "git.ophivana.moe/cat/fortify/internal/xcb" +) + +func Fatal(msg ...any) { + fmt.Println(msg...) + BeforeExit() + os.Exit(1) +} + +func BeforeExit() { + if u == nil { + fmt.Println("warn: beforeExit called before app init") + return + } + + if statePath == "" { + if system.V.Verbose { + fmt.Println("State path is unset") + } + } else { + if err := os.Remove(statePath); err != nil && !errors.Is(err, fs.ErrNotExist) { + fmt.Println("Error removing state file:", err) + } + } + + if d, err := readLaunchers(); err != nil { + fmt.Println("Error reading active launchers:", err) + os.Exit(1) + } else if len(d) > 0 { + // other launchers are still active + if system.V.Verbose { + fmt.Printf("Found %d active launchers, exiting without cleaning up\n", len(d)) + } + return + } + + if system.V.Verbose { + fmt.Println("No other launchers active, will clean up") + } + + if xcbActionComplete { + if system.V.Verbose { + fmt.Printf("X11: Removing XHost entry SI:localuser:%s\n", u.Username) + } + if err := xcb.ChangeHosts(xcb.HostModeDelete, xcb.FamilyServerInterpreted, "localuser\x00"+u.Username); err != nil { + fmt.Println("Error removing XHost entry:", err) + } + } + + for _, candidate := range cleanupCandidate { + if err := acl.UpdatePerm(candidate, uid); err != nil { + fmt.Printf("Error stripping ACL entry from '%s': %s\n", candidate, err) + } + if system.V.Verbose { + fmt.Printf("Stripped ACL entry for user '%s' from '%s'\n", u.Username, candidate) + } + } +} diff --git a/internal/state/register.go b/internal/state/register.go new file mode 100644 index 00000000..2fff565e --- /dev/null +++ b/internal/state/register.go @@ -0,0 +1,12 @@ +package state + +func RegisterRevertPath(p string) { + cleanupCandidate = append(cleanupCandidate, p) +} + +func XcbActionComplete() { + if xcbActionComplete { + Fatal("xcb inserted twice") + } + xcbActionComplete = true +} diff --git a/internal/state/track.go b/internal/state/track.go new file mode 100644 index 00000000..913d684d --- /dev/null +++ b/internal/state/track.go @@ -0,0 +1,115 @@ +package state + +import ( + "encoding/gob" + "errors" + "flag" + "fmt" + "io/fs" + "os" + "os/exec" + "path" + "strconv" + + "git.ophivana.moe/cat/fortify/internal/system" +) + +// we unfortunately have to assume there are never races between processes +// this and launcher should eventually be replaced by a server process + +var ( + stateActionEarly bool + statePath string + cleanupCandidate []string + xcbActionComplete bool +) + +type launcherState struct { + PID int + Launcher string + Argv []string + Command []string +} + +func init() { + flag.BoolVar(&stateActionEarly, "state", false, "query state value of current active launchers") +} + +func Early() { + if !stateActionEarly { + return + } + + launchers, err := readLaunchers() + if err != nil { + fmt.Println("Error reading launchers:", err) + os.Exit(1) + } + + fmt.Println("\tPID\tLauncher") + for _, state := range launchers { + fmt.Printf("\t%d\t%s\nCommand: %s\nArgv: %s\n", state.PID, state.Launcher, state.Command, state.Argv) + } + + os.Exit(0) +} + +// SaveProcess called after process start, before wait +func SaveProcess(uid string, cmd *exec.Cmd) error { + statePath = path.Join(system.V.RunDir, uid, strconv.Itoa(cmd.Process.Pid)) + state := launcherState{ + PID: cmd.Process.Pid, + Launcher: cmd.Path, + Argv: cmd.Args, + Command: command, + } + + if err := os.Mkdir(path.Join(system.V.RunDir, uid), 0700); err != nil && !errors.Is(err, fs.ErrExist) { + return err + } + + if f, err := os.OpenFile(statePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600); err != nil { + return err + } else { + defer func() { + if f.Close() != nil { + // unreachable + panic("state file closed prematurely") + } + }() + return gob.NewEncoder(f).Encode(state) + } +} + +func readLaunchers() ([]*launcherState, error) { + var f *os.File + var r []*launcherState + launcherPrefix := path.Join(system.V.RunDir, u.Uid) + + if pl, err := os.ReadDir(launcherPrefix); err != nil { + return nil, err + } else { + for _, e := range pl { + if err = func() error { + if f, err = os.Open(path.Join(launcherPrefix, e.Name())); err != nil { + return err + } else { + defer func() { + if f.Close() != nil { + // unreachable + panic("foreign state file closed prematurely") + } + }() + + var s launcherState + r = append(r, &s) + return gob.NewDecoder(f).Decode(&s) + } + }(); err != nil { + return nil, err + } + } + } + + return r, nil +} diff --git a/internal/state/value.go b/internal/state/value.go new file mode 100644 index 00000000..cb20818c --- /dev/null +++ b/internal/state/value.go @@ -0,0 +1,21 @@ +package state + +import ( + "os/user" +) + +var ( + u *user.User + uid int + command []string +) + +func Set(val user.User, c []string, d int) { + if u != nil { + panic("state set twice") + } + + u = &val + command = c + uid = d +} |
