* IDState cleaned up. Should work on all *NIXes now. * Can now get IDState of arbitrary PID. * Shuffled some env stuff around.
159 lines
3.3 KiB
Go
159 lines
3.3 KiB
Go
//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
|
|
}
|