package sysutils import ( "fmt" "os" "strconv" "strings" "golang.org/x/sys/unix" "r00t2.io/sysutils/envs" "r00t2.io/sysutils/errs" ) // 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("SUDO_COMMAND") ids.SudoEnvHome = envs.HasEnv("SUDO_HOME") ids.SudoEnvGroup = envs.HasEnv("SUDO_GID") ids.SudoEnvUser = envs.HasEnv("SUDO_UID") || envs.HasEnv("SUDO_USER") 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 } // NsToInode splits a namespace identifier (e.g. `net:[12345]`) to its type (e.g. `net`) and inode (e.g. `12345`). func NsToInode(ns string) (typ string, inode uint64, err error) { var fields []string fields = strings.SplitN(ns, ":", 2) if len(fields) != 2 { err = errs.ErrInvalidNs return } fields[1] = strings.TrimPrefix(fields[1], "[") fields[1] = strings.TrimSuffix(fields[1], "]") if inode, err = strconv.ParseUint(fields[1], 10, 64); err != nil { return } typ = fields[0] return }