lookup_unix.go 3.9 KB

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