lookup_unix.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
  2. // +build darwin dragonfly freebsd linux netbsd openbsd solaris
  3. package user
  4. import (
  5. "io"
  6. "os"
  7. "strconv"
  8. "golang.org/x/sys/unix"
  9. )
  10. // Unix-specific path to the passwd and group formatted files.
  11. const (
  12. unixPasswdPath = "/etc/passwd"
  13. unixGroupPath = "/etc/group"
  14. )
  15. // LookupUser looks up a user by their username in /etc/passwd. If the user
  16. // cannot be found (or there is no /etc/passwd file on the filesystem), then
  17. // LookupUser returns an error.
  18. func LookupUser(username string) (User, error) {
  19. return lookupUserFunc(func(u User) bool {
  20. return u.Name == username
  21. })
  22. }
  23. // LookupUid looks up a user by their user id in /etc/passwd. If the user cannot
  24. // be found (or there is no /etc/passwd file on the filesystem), then LookupId
  25. // returns an error.
  26. func LookupUid(uid int) (User, error) {
  27. return lookupUserFunc(func(u User) bool {
  28. return u.Uid == uid
  29. })
  30. }
  31. func lookupUserFunc(filter func(u User) bool) (User, error) {
  32. // Get operating system-specific passwd reader-closer.
  33. passwd, err := GetPasswd()
  34. if err != nil {
  35. return User{}, err
  36. }
  37. defer passwd.Close()
  38. // Get the users.
  39. users, err := ParsePasswdFilter(passwd, filter)
  40. if err != nil {
  41. return User{}, err
  42. }
  43. // No user entries found.
  44. if len(users) == 0 {
  45. return User{}, ErrNoPasswdEntries
  46. }
  47. // Assume the first entry is the "correct" one.
  48. return users[0], nil
  49. }
  50. // LookupGroup looks up a group by its name in /etc/group. If the group cannot
  51. // be found (or there is no /etc/group file on the filesystem), then LookupGroup
  52. // returns an error.
  53. func LookupGroup(groupname string) (Group, error) {
  54. return lookupGroupFunc(func(g Group) bool {
  55. return g.Name == groupname
  56. })
  57. }
  58. // LookupGid looks up a group by its group id in /etc/group. If the group cannot
  59. // be found (or there is no /etc/group file on the filesystem), then LookupGid
  60. // returns an error.
  61. func LookupGid(gid int) (Group, error) {
  62. return lookupGroupFunc(func(g Group) bool {
  63. return g.Gid == gid
  64. })
  65. }
  66. func lookupGroupFunc(filter func(g Group) bool) (Group, error) {
  67. // Get operating system-specific group reader-closer.
  68. group, err := GetGroup()
  69. if err != nil {
  70. return Group{}, err
  71. }
  72. defer group.Close()
  73. // Get the users.
  74. groups, err := ParseGroupFilter(group, filter)
  75. if err != nil {
  76. return Group{}, err
  77. }
  78. // No user entries found.
  79. if len(groups) == 0 {
  80. return Group{}, ErrNoGroupEntries
  81. }
  82. // Assume the first entry is the "correct" one.
  83. return groups[0], nil
  84. }
  85. func GetPasswdPath() (string, error) {
  86. return unixPasswdPath, nil
  87. }
  88. func GetPasswd() (io.ReadCloser, error) {
  89. return os.Open(unixPasswdPath)
  90. }
  91. func GetGroupPath() (string, error) {
  92. return unixGroupPath, nil
  93. }
  94. func GetGroup() (io.ReadCloser, error) {
  95. return os.Open(unixGroupPath)
  96. }
  97. // CurrentUser looks up the current user by their user id in /etc/passwd. If the
  98. // user cannot be found (or there is no /etc/passwd file on the filesystem),
  99. // then CurrentUser returns an error.
  100. func CurrentUser() (User, error) {
  101. return LookupUid(unix.Getuid())
  102. }
  103. // CurrentGroup looks up the current user's group by their primary group id's
  104. // entry in /etc/passwd. If the group cannot be found (or there is no
  105. // /etc/group file on the filesystem), then CurrentGroup returns an error.
  106. func CurrentGroup() (Group, error) {
  107. return LookupGid(unix.Getgid())
  108. }
  109. func currentUserSubIDs(fileName string) ([]SubID, error) {
  110. u, err := CurrentUser()
  111. if err != nil {
  112. return nil, err
  113. }
  114. filter := func(entry SubID) bool {
  115. return entry.Name == u.Name || entry.Name == strconv.Itoa(u.Uid)
  116. }
  117. return ParseSubIDFileFilter(fileName, filter)
  118. }
  119. func CurrentUserSubUIDs() ([]SubID, error) {
  120. return currentUserSubIDs("/etc/subuid")
  121. }
  122. func CurrentUserSubGIDs() ([]SubID, error) {
  123. return currentUserSubIDs("/etc/subgid")
  124. }
  125. func CurrentProcessUIDMap() ([]IDMap, error) {
  126. return ParseIDMapFile("/proc/self/uid_map")
  127. }
  128. func CurrentProcessGIDMap() ([]IDMap, error) {
  129. return ParseIDMapFile("/proc/self/gid_map")
  130. }