github.com/rminnich/u-root@v7.0.0+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  }