github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/cmds/core/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 // +build !plan9 6 7 // id displays the user id, group id, and groups of the calling process. 8 // 9 // Synopsis: 10 // id [-gGnu] 11 // 12 // Description: 13 // id displays the uid, gid and groups of the calling process 14 // 15 // Options: 16 // -g, --group print only the effective group ID 17 // -G, --groups print all group IDs 18 // -n, --name print a name instead of a number, for -ugG 19 // -u, --user print only the effective user ID 20 // -r, --user print real ID instead of effective ID 21 package main 22 23 import ( 24 "flag" 25 "fmt" 26 "log" 27 "strconv" 28 "strings" 29 "syscall" 30 ) 31 32 var ( 33 GroupFile = "/etc/group" 34 PasswdFile = "/etc/passwd" 35 36 flags struct { 37 group bool 38 groups bool 39 name bool 40 user bool 41 real bool 42 } 43 ) 44 45 func correctFlags(flags ...bool) bool { 46 n := 0 47 for _, v := range flags { 48 if v { 49 n++ 50 } 51 } 52 return !(n > 1) 53 } 54 55 func init() { 56 flag.BoolVar(&flags.group, "g", false, "print only the effective group ID") 57 flag.BoolVar(&flags.groups, "G", false, "print all group IDs") 58 flag.BoolVar(&flags.name, "n", false, "print a name instead of a number, for -ugG") 59 flag.BoolVar(&flags.user, "u", false, "print only the effective user ID") 60 flag.BoolVar(&flags.real, "r", false, "print real ID instead of effective ID") 61 } 62 63 type User struct { 64 name string 65 uid int 66 gid int 67 groups map[int]string 68 } 69 70 func (u *User) UID() int { 71 return u.uid 72 } 73 74 func (u *User) GID() int { 75 return u.gid 76 } 77 78 func (u *User) Name() string { 79 return u.name 80 } 81 82 func (u *User) Groups() map[int]string { 83 return u.groups 84 } 85 86 func (u *User) GIDName() string { 87 val := u.Groups()[u.UID()] 88 return val 89 } 90 91 // NewUser is a factory method for the User type. 92 func NewUser(username string, users *Users, groups *Groups) (*User, error) { 93 var groupsNumbers []int 94 95 u := &User{groups: make(map[int]string)} 96 if len(username) == 0 { // no username provided, get current 97 if flags.real { 98 u.uid = syscall.Geteuid() 99 u.gid = syscall.Getegid() 100 } else { 101 u.uid = syscall.Getuid() 102 u.gid = syscall.Getgid() 103 } 104 groupsNumbers, _ = syscall.Getgroups() 105 if v, err := users.GetUser(u.uid); err == nil { 106 u.name = v 107 } else { 108 u.name = strconv.Itoa(u.uid) 109 } 110 } else { 111 if v, err := users.GetUID(username); err == nil { // user is username 112 u.name = username 113 u.uid = v 114 } else { 115 if uid, err := strconv.Atoi(username); err == nil { // user is valid int 116 if v, err := users.GetUser(uid); err == nil { // user is valid uid 117 u.name = v 118 u.uid = uid 119 } 120 } else { 121 return nil, fmt.Errorf("id: no such user or uid: %s", username) 122 } 123 } 124 u.gid, _ = users.GetGID(u.uid) 125 groupsNumbers = append([]int{u.gid}, groups.UserGetGIDs(u.name)...) 126 // FIXME: not yet implemented group listing lookups 127 } 128 129 for _, groupNum := range groupsNumbers { 130 if groupName, err := groups.GetGroup(groupNum); err == nil { 131 u.groups[groupNum] = groupName 132 } else { 133 u.groups[groupNum] = strconv.Itoa(groupNum) 134 } 135 } 136 137 return u, nil 138 } 139 140 // IDCommand runs the "id" with the current user's information. 141 func IDCommand(u User) { 142 if !flags.groups { 143 if flags.user { 144 if flags.name { 145 fmt.Println(u.Name()) 146 return 147 } 148 fmt.Println(u.UID()) 149 return 150 } else if flags.group { 151 if flags.name { 152 fmt.Println(u.GIDName()) 153 return 154 } 155 fmt.Println(u.GID()) 156 return 157 } 158 159 fmt.Printf("uid=%d(%s) ", u.UID(), u.Name()) 160 fmt.Printf("gid=%d(%s) ", u.GID(), u.GIDName()) 161 } 162 163 if !flags.groups { 164 fmt.Print("groups=") 165 } 166 167 var groupOutput []string 168 169 for gid, name := range u.Groups() { 170 171 if !flags.groups { 172 groupOutput = append(groupOutput, fmt.Sprintf("%d(%s)", gid, name)) 173 174 } else { 175 if flags.name { 176 groupOutput = append(groupOutput, fmt.Sprintf("%s ", name)) 177 } else { 178 groupOutput = append(groupOutput, fmt.Sprintf("%d ", gid)) 179 } 180 } 181 } 182 183 sep := "," 184 if flags.groups { 185 sep = "" 186 } 187 188 fmt.Println(strings.Join(groupOutput, sep)) 189 } 190 191 func main() { 192 flag.Parse() 193 if !correctFlags(flags.groups, flags.group, flags.user) { 194 log.Fatalf("id: cannot print \"only\" of more than one choice") 195 196 } 197 if flags.name && !(flags.groups || flags.group || flags.user) { 198 log.Fatalf("id: cannot print only names in default format") 199 } 200 if len(flag.Arg(0)) != 0 && flags.real { 201 log.Fatalf("id: cannot print only names or real IDs in default format") 202 } 203 204 users, err := NewUsers(PasswdFile) 205 if err != nil { 206 log.Printf("id: unable to read %s: %v", PasswdFile, err) 207 } 208 groups, err := NewGroups(GroupFile) 209 if err != nil { 210 log.Printf("id: unable to read %s: %v", PasswdFile, err) 211 } 212 213 user, err := NewUser(flag.Arg(0), users, groups) 214 if err != nil { 215 log.Fatalf("id: %s", err) 216 } 217 218 IDCommand(*user) 219 }