//go:build !(windows || plan9 || wasip1 || js || ios) package sysutils import ( "fmt" `math` "os" `github.com/shirou/gopsutil/v3/process` "golang.org/x/sys/unix" "r00t2.io/sysutils/envs" `r00t2.io/sysutils/errs` `r00t2.io/sysutils/internal` ) // GetIDState returns current ID/elevation information. An IDState should *not* be explicitly created/defined. func GetIDState() (ids IDState) { var err error ids.RUID, ids.EUID, ids.SUID = unix.Getresuid() ids.uidsChecked = true ids.RGID, ids.EGID, ids.SGID = unix.Getresgid() ids.gidsChecked = true ids.SudoEnvCmd = envs.HasEnv(envSudoCmd) ids.SudoEnvHome = envs.HasEnv(envSudoHome) ids.SudoEnvGroup = envs.HasEnv(envSudoGrp) ids.SudoEnvUser = envs.HasEnv(envSudoUid) || envs.HasEnv(envSudoUname) if ids.SudoEnvCmd || ids.SudoEnvHome || ids.SudoEnvGroup || ids.SudoEnvUser { ids.SudoEnvVars = true } ids.sudoChecked = true // PID 1 will *always* be root, so that can return a false positive for sudo. if os.Getppid() != 1 { ids.stat = new(unix.Stat_t) if err = unix.Stat( fmt.Sprintf("/proc/%d/stat", os.Getppid()), ids.stat, ); err != nil { err = nil } else { ids.PPIDUidMatch = ids.RUID == int(ids.stat.Uid) ids.ppidUidChecked = true ids.PPIDGidMatch = ids.RGID == int(ids.stat.Gid) ids.ppidGidChecked = true } } else { ids.ppidUidChecked = true ids.ppidGidChecked = true } return } // GetIDStateProc is like GetIDState but for an arbitrary PID. func GetIDStateProc(pid uint32) (ids IDState, err error) { var i32 int32 var ints []int32 var sudoUid bool var sudoUname bool var proc *process.Process var envMap map[string]string if pid > math.MaxInt32 { err = errs.ErrHighPid return } ids = IDState{ RUID: -1, EUID: -1, SUID: -1, RGID: -1, EGID: -1, SGID: -1, } if proc, err = process.NewProcess(int32(pid)); err != nil { return } // UIDs if ints, err = proc.Uids(); err != nil { return } if ints != nil && len(ints) > 0 { if len(ints) >= 3 { ids.SUID = int(ints[2]) } if len(ints) >= 2 { ids.EUID = int(ints[1]) } if len(ints) >= 1 { ids.RUID = int(ints[0]) } } ids.uidsChecked = true // GIDs if ints, err = proc.Gids(); err != nil { return } if ints != nil && len(ints) > 0 { if len(ints) >= 3 { ids.SGID = int(ints[2]) } if len(ints) >= 2 { ids.EGID = int(ints[1]) } if len(ints) >= 1 { ids.SGID = int(ints[0]) } } ids.gidsChecked = true // Sudo (env check) if envMap, err = internal.GetPidEnvMap(uint32(pid)); err != nil { return } _, ids.SudoEnvCmd = envMap[envSudoCmd] _, ids.SudoEnvHome = envMap[envSudoHome] _, ids.SudoEnvGroup = envMap[envSudoGrp] _, sudoUid = envMap[envSudoUid] _, sudoUname = envMap[envSudoUname] ids.SudoEnvUser = sudoUid || sudoUname if ids.SudoEnvCmd || ids.SudoEnvHome || ids.SudoEnvGroup || ids.SudoEnvUser { ids.SudoEnvVars = true } ids.sudoChecked = true // Sudo (PPID check) if i32, err = proc.Ppid(); err != nil { return } if i32 != 1 { ids.stat = new(unix.Stat_t) if err = unix.Stat( fmt.Sprintf("/proc/%d/stat", i32), ids.stat, ); err != nil { err = nil } else { ids.PPIDUidMatch = ids.RUID == int(ids.stat.Uid) ids.ppidUidChecked = true ids.PPIDGidMatch = ids.SGID == int(ids.stat.Gid) ids.ppidGidChecked = true } } else { ids.ppidUidChecked = true ids.ppidGidChecked = true } return }