gopkg.in/hugelgupf/u-root.v2@v2.0.0-20180831055005-3f8fdb0ce09d/cmds/id/id.go (about) 1 // Copyright 2017-2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Synopsis: 6 // id [-gGnu] 7 // 8 // Description: 9 // id displays the uid, guid and groups of the calling process 10 // Options: 11 // -g, --group print only the effective group ID 12 // -G, --groups print all group IDs 13 // -n, --name print a name instead of a number, for -ugG 14 // -u, --user print only the effective user ID 15 package main 16 17 import ( 18 "bufio" 19 "flag" 20 "fmt" 21 "log" 22 "os" 23 "strconv" 24 "strings" 25 "syscall" 26 ) 27 28 var ( 29 GroupFile = "/etc/group" 30 PasswdFile = "/etc/passwd" 31 32 flags struct { 33 group bool 34 groups bool 35 name bool 36 user bool 37 } 38 ) 39 40 func correctFlags(flags ...bool) bool { 41 n := 0 42 for _, v := range flags { 43 if v { 44 n++ 45 } 46 } 47 return !(n > 1) 48 } 49 50 func init() { 51 flag.BoolVar(&flags.group, "g", false, "print only the effective group ID") 52 flag.BoolVar(&flags.groups, "G", false, "print all group IDs") 53 flag.BoolVar(&flags.name, "n", false, "print a name instead of a number, for -ugG") 54 flag.BoolVar(&flags.user, "u", false, "print only the effective user ID") 55 } 56 57 type User struct { 58 name string 59 uid int 60 euid int 61 gid int 62 groups map[int]string 63 } 64 65 // readGroups reads the GroupFile for groups. 66 // It assumes the format "name:passwd:number:groupList". 67 func readGroups() (map[int]string, error) { 68 groupFile, err := os.Open(GroupFile) 69 if err != nil { 70 return nil, err 71 } 72 73 var groupInfo []string 74 75 groupsMap := make(map[int]string) 76 groupScanner := bufio.NewScanner(groupFile) 77 78 for groupScanner.Scan() { 79 groupInfo = strings.Split(groupScanner.Text(), ":") 80 groupNum, err := strconv.Atoi(groupInfo[2]) 81 if err != nil { 82 return nil, err 83 } 84 85 groupsMap[groupNum] = groupInfo[0] 86 } 87 88 return groupsMap, nil 89 } 90 91 func (u *User) UID() int { 92 return u.uid 93 } 94 95 func (u *User) GetEuid() int { 96 return u.euid 97 } 98 99 func (u *User) GID() int { 100 return u.gid 101 } 102 103 func (u *User) Name() string { 104 return u.name 105 } 106 107 func (u *User) Groups() map[int]string { 108 return u.groups 109 } 110 111 func (u *User) GIDName() string { 112 val := u.Groups()[u.UID()] 113 return val 114 } 115 116 // NewUser is a factory method for the User type. 117 func NewUser() (*User, error) { 118 u := &User{"", syscall.Getuid(), syscall.Geteuid(), syscall.Getgid(), make(map[int]string)} 119 120 groupsNumbers, err := syscall.Getgroups() 121 if err != nil { 122 return nil, err 123 } 124 125 // Read from groupFile for names and numbers 126 groupsMap, err := readGroups() 127 if err != nil { 128 return nil, err 129 } 130 131 for _, groupNum := range groupsNumbers { 132 if groupName, ok := groupsMap[groupNum]; ok { 133 u.groups[groupNum] = groupName 134 } else { 135 return nil, fmt.Errorf("Inconsistent %s file", GroupFile) 136 } 137 } 138 139 passwdFile, err := os.Open(PasswdFile) 140 if err != nil { 141 return nil, err 142 } 143 144 // Read from passwdFile for the users name 145 var passwdInfo []string 146 147 passwdScanner := bufio.NewScanner(passwdFile) 148 149 for passwdScanner.Scan() { 150 passwdInfo = strings.Split(passwdScanner.Text(), ":") 151 if val, err := strconv.Atoi(passwdInfo[2]); err != nil { 152 return nil, err 153 } else if val == u.UID() { 154 u.name = passwdInfo[0] 155 break 156 } 157 } 158 159 if u.name == "" { 160 return nil, fmt.Errorf("User is not in %s", PasswdFile) 161 } 162 163 return u, nil 164 } 165 166 // IDCommand runs the "id" with the current user's information. 167 func IDCommand(u User) { 168 if !flags.groups { 169 if flags.user { 170 if flags.name { 171 fmt.Println(u.Name()) 172 return 173 } 174 fmt.Println(u.UID()) 175 return 176 } else if flags.group { 177 if flags.name { 178 fmt.Println(u.GIDName()) 179 return 180 } 181 fmt.Println(u.GID()) 182 return 183 } 184 185 fmt.Printf("uid=%d(%s) ", u.UID(), u.Name()) 186 fmt.Printf("gid=%d(%s) ", u.GID(), u.GIDName()) 187 } 188 189 if !flags.groups { 190 fmt.Print("groups=") 191 } 192 193 var groupOutput []string 194 195 for gid, name := range u.Groups() { 196 197 if !flags.groups { 198 groupOutput = append(groupOutput, fmt.Sprintf("%d(%s)", gid, name)) 199 200 } else { 201 if flags.name { 202 groupOutput = append(groupOutput, fmt.Sprintf("%s ", name)) 203 } else { 204 groupOutput = append(groupOutput, fmt.Sprintf("%d ", gid)) 205 } 206 } 207 } 208 209 sep := "," 210 if flags.groups { 211 sep = "" 212 } 213 214 fmt.Println(strings.Join(groupOutput, sep)) 215 } 216 217 func main() { 218 flag.Parse() 219 if !correctFlags(flags.groups, flags.group, flags.user) { 220 log.Fatalf("id: cannot print \"only\" of more than one choice") 221 222 } 223 if flags.name && !(flags.groups || flags.group || flags.user) { 224 log.Fatalf("id: cannot print only names in default format") 225 } 226 227 currentUser, err := NewUser() 228 if err != nil { 229 log.Fatalf("id: %s", err) 230 } 231 232 IDCommand(*currentUser) 233 }