diff options
Diffstat (limited to 'pkg/chrootuser')
-rw-r--r-- | pkg/chrootuser/user.go | 108 | ||||
-rw-r--r-- | pkg/chrootuser/user_basic.go | 27 | ||||
-rw-r--r-- | pkg/chrootuser/user_linux.go | 293 |
3 files changed, 0 insertions, 428 deletions
diff --git a/pkg/chrootuser/user.go b/pkg/chrootuser/user.go deleted file mode 100644 index c83dcc230..000000000 --- a/pkg/chrootuser/user.go +++ /dev/null @@ -1,108 +0,0 @@ -package chrootuser - -import ( - "os/user" - "strconv" - "strings" - - "github.com/pkg/errors" -) - -var ( - // ErrNoSuchUser indicates that the user provided by the caller does not - // exist in /etc/passws - ErrNoSuchUser = errors.New("user does not exist in /etc/passwd") -) - -// GetUser will return the uid, gid of the user specified in the userspec -// it will use the /etc/passwd and /etc/group files inside of the rootdir -// to return this information. -// userspec format [user | user:group | uid | uid:gid | user:gid | uid:group ] -func GetUser(rootdir, userspec string) (uint32, uint32, error) { - var gid64 uint64 - var gerr error = user.UnknownGroupError("error looking up group") - - spec := strings.SplitN(userspec, ":", 2) - userspec = spec[0] - groupspec := "" - if userspec == "" { - return 0, 0, nil - } - if len(spec) > 1 { - groupspec = spec[1] - } - - uid64, uerr := strconv.ParseUint(userspec, 10, 32) - if uerr == nil && groupspec == "" { - // We parsed the user name as a number, and there's no group - // component, so try to look up the primary GID of the user who - // has this UID. - var name string - name, gid64, gerr = lookupGroupForUIDInContainer(rootdir, uid64) - if gerr == nil { - userspec = name - } else { - // Leave userspec alone, but swallow the error and just - // use GID 0. - gid64 = 0 - gerr = nil - } - } - if uerr != nil { - // The user ID couldn't be parsed as a number, so try to look - // up the user's UID and primary GID. - uid64, gid64, uerr = lookupUserInContainer(rootdir, userspec) - gerr = uerr - } - - if groupspec != "" { - // We have a group name or number, so parse it. - gid64, gerr = strconv.ParseUint(groupspec, 10, 32) - if gerr != nil { - // The group couldn't be parsed as a number, so look up - // the group's GID. - gid64, gerr = lookupGroupInContainer(rootdir, groupspec) - } - } - - if uerr == nil && gerr == nil { - return uint32(uid64), uint32(gid64), nil - } - - err := errors.Wrapf(uerr, "error determining run uid") - if uerr == nil { - err = errors.Wrapf(gerr, "error determining run gid") - } - return 0, 0, err -} - -// GetGroup returns the gid by looking it up in the /etc/group file -// groupspec format [ group | gid ] -func GetGroup(rootdir, groupspec string) (uint32, error) { - gid64, gerr := strconv.ParseUint(groupspec, 10, 32) - if gerr != nil { - // The group couldn't be parsed as a number, so look up - // the group's GID. - gid64, gerr = lookupGroupInContainer(rootdir, groupspec) - } - if gerr != nil { - return 0, errors.Wrapf(gerr, "error looking up group for gid %q", groupspec) - } - return uint32(gid64), nil -} - -// GetAdditionalGroupsForUser returns a list of gids that userid is associated with -func GetAdditionalGroupsForUser(rootdir string, userid uint64) ([]uint32, error) { - gids, err := lookupAdditionalGroupsForUIDInContainer(rootdir, userid) - if err != nil { - return nil, errors.Wrapf(err, "error looking up supplemental groups for uid %d", userid) - } - return gids, nil -} - -// LookupUIDInContainer returns username and gid associated with a UID in a container -// it will use the /etc/passwd files inside of the rootdir -// to return this information. -func LookupUIDInContainer(rootdir string, uid uint64) (user string, gid uint64, err error) { - return lookupUIDInContainer(rootdir, uid) -} diff --git a/pkg/chrootuser/user_basic.go b/pkg/chrootuser/user_basic.go deleted file mode 100644 index 79b0b24b5..000000000 --- a/pkg/chrootuser/user_basic.go +++ /dev/null @@ -1,27 +0,0 @@ -// +build !linux - -package chrootuser - -import ( - "github.com/pkg/errors" -) - -func lookupUserInContainer(rootdir, username string) (uint64, uint64, error) { - return 0, 0, errors.New("user lookup not supported") -} - -func lookupGroupInContainer(rootdir, groupname string) (uint64, error) { - return 0, errors.New("group lookup not supported") -} - -func lookupGroupForUIDInContainer(rootdir string, userid uint64) (string, uint64, error) { - return "", 0, errors.New("primary group lookup by uid not supported") -} - -func lookupAdditionalGroupsForUIDInContainer(rootdir string, userid uint64) (gid []uint32, err error) { - return nil, errors.New("supplemental groups list lookup by uid not supported") -} - -func lookupUIDInContainer(rootdir string, uid uint64) (string, uint64, error) { - return "", 0, errors.New("UID lookup not supported") -} diff --git a/pkg/chrootuser/user_linux.go b/pkg/chrootuser/user_linux.go deleted file mode 100644 index 583eca569..000000000 --- a/pkg/chrootuser/user_linux.go +++ /dev/null @@ -1,293 +0,0 @@ -// +build linux - -package chrootuser - -import ( - "bufio" - "flag" - "fmt" - "io" - "os" - "os/exec" - "os/user" - "strconv" - "strings" - "sync" - - "github.com/containers/storage/pkg/reexec" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" -) - -const ( - openChrootedCommand = "chrootuser-open" -) - -func init() { - reexec.Register(openChrootedCommand, openChrootedFileMain) -} - -func openChrootedFileMain() { - status := 0 - flag.Parse() - if len(flag.Args()) < 1 { - os.Exit(1) - } - // Our first parameter is the directory to chroot into. - if err := unix.Chdir(flag.Arg(0)); err != nil { - fmt.Fprintf(os.Stderr, "chdir(): %v", err) - os.Exit(1) - } - if err := unix.Chroot(flag.Arg(0)); err != nil { - fmt.Fprintf(os.Stderr, "chroot(): %v", err) - os.Exit(1) - } - // Anything else is a file we want to dump out. - for _, filename := range flag.Args()[1:] { - f, err := os.Open(filename) - if err != nil { - fmt.Fprintf(os.Stderr, "open(%q): %v", filename, err) - status = 1 - continue - } - _, err = io.Copy(os.Stdout, f) - if err != nil { - fmt.Fprintf(os.Stderr, "read(%q): %v", filename, err) - } - f.Close() - } - os.Exit(status) -} - -func openChrootedFile(rootdir, filename string) (*exec.Cmd, io.ReadCloser, error) { - // The child process expects a chroot and one or more filenames that - // will be consulted relative to the chroot directory and concatenated - // to its stdout. Start it up. - cmd := reexec.Command(openChrootedCommand, rootdir, filename) - stdout, err := cmd.StdoutPipe() - if err != nil { - return nil, nil, err - } - err = cmd.Start() - if err != nil { - return nil, nil, err - } - // Hand back the child's stdout for reading, and the child to reap. - return cmd, stdout, nil -} - -var ( - lookupUser, lookupGroup sync.Mutex -) - -type lookupPasswdEntry struct { - name string - uid uint64 - gid uint64 -} -type lookupGroupEntry struct { - name string - gid uint64 - user string -} - -func readWholeLine(rc *bufio.Reader) ([]byte, error) { - line, isPrefix, err := rc.ReadLine() - if err != nil { - return nil, err - } - for isPrefix { - // We didn't get a whole line. Keep reading chunks until we find an end of line, and discard them. - for isPrefix { - logrus.Debugf("discarding partial line %q", string(line)) - _, isPrefix, err = rc.ReadLine() - if err != nil { - return nil, err - } - } - // That last read was the end of a line, so now we try to read the (beginning of?) the next line. - line, isPrefix, err = rc.ReadLine() - if err != nil { - return nil, err - } - } - return line, nil -} - -func parseNextPasswd(rc *bufio.Reader) *lookupPasswdEntry { - line, err := readWholeLine(rc) - if err != nil { - return nil - } - fields := strings.Split(string(line), ":") - if len(fields) < 7 { - return nil - } - uid, err := strconv.ParseUint(fields[2], 10, 32) - if err != nil { - return nil - } - gid, err := strconv.ParseUint(fields[3], 10, 32) - if err != nil { - return nil - } - return &lookupPasswdEntry{ - name: fields[0], - uid: uid, - gid: gid, - } -} - -func parseNextGroup(rc *bufio.Reader) *lookupGroupEntry { - line, err := readWholeLine(rc) - if err != nil { - return nil - } - fields := strings.Split(string(line), ":") - if len(fields) < 4 { - return nil - } - gid, err := strconv.ParseUint(fields[2], 10, 32) - if err != nil { - return nil - } - return &lookupGroupEntry{ - name: fields[0], - gid: gid, - user: fields[3], - } -} - -func lookupUserInContainer(rootdir, username string) (uid uint64, gid uint64, err error) { - cmd, f, err := openChrootedFile(rootdir, "/etc/passwd") - if err != nil { - return 0, 0, err - } - defer func() { - _ = cmd.Wait() - }() - rc := bufio.NewReader(f) - defer f.Close() - - lookupUser.Lock() - defer lookupUser.Unlock() - - pwd := parseNextPasswd(rc) - for pwd != nil { - if pwd.name != username { - pwd = parseNextPasswd(rc) - continue - } - return pwd.uid, pwd.gid, nil - } - - return 0, 0, user.UnknownUserError(fmt.Sprintf("error looking up user %q", username)) -} - -func lookupGroupForUIDInContainer(rootdir string, userid uint64) (username string, gid uint64, err error) { - cmd, f, err := openChrootedFile(rootdir, "/etc/passwd") - if err != nil { - return "", 0, err - } - defer func() { - _ = cmd.Wait() - }() - rc := bufio.NewReader(f) - defer f.Close() - - lookupUser.Lock() - defer lookupUser.Unlock() - - pwd := parseNextPasswd(rc) - for pwd != nil { - if pwd.uid != userid { - pwd = parseNextPasswd(rc) - continue - } - return pwd.name, pwd.gid, nil - } - - return "", 0, ErrNoSuchUser -} - -func lookupAdditionalGroupsForUIDInContainer(rootdir string, userid uint64) (gid []uint32, err error) { - // Get the username associated with userid - username, _, err := lookupGroupForUIDInContainer(rootdir, userid) - if err != nil { - return nil, err - } - - cmd, f, err := openChrootedFile(rootdir, "/etc/group") - if err != nil { - return nil, err - } - defer func() { - _ = cmd.Wait() - }() - rc := bufio.NewReader(f) - defer f.Close() - - lookupGroup.Lock() - defer lookupGroup.Unlock() - - grp := parseNextGroup(rc) - for grp != nil { - if strings.Contains(grp.user, username) { - gid = append(gid, uint32(grp.gid)) - } - grp = parseNextGroup(rc) - } - return gid, nil -} - -func lookupGroupInContainer(rootdir, groupname string) (gid uint64, err error) { - cmd, f, err := openChrootedFile(rootdir, "/etc/group") - if err != nil { - return 0, err - } - defer func() { - _ = cmd.Wait() - }() - rc := bufio.NewReader(f) - defer f.Close() - - lookupGroup.Lock() - defer lookupGroup.Unlock() - - grp := parseNextGroup(rc) - for grp != nil { - if grp.name != groupname { - grp = parseNextGroup(rc) - continue - } - return grp.gid, nil - } - - return 0, user.UnknownGroupError(fmt.Sprintf("error looking up group %q", groupname)) -} - -func lookupUIDInContainer(rootdir string, uid uint64) (string, uint64, error) { - cmd, f, err := openChrootedFile(rootdir, "/etc/passwd") - if err != nil { - return "", 0, err - } - defer func() { - _ = cmd.Wait() - }() - rc := bufio.NewReader(f) - defer f.Close() - - lookupUser.Lock() - defer lookupUser.Unlock() - - pwd := parseNextPasswd(rc) - for pwd != nil { - if pwd.uid != uid { - pwd = parseNextPasswd(rc) - continue - } - return pwd.name, pwd.gid, nil - } - - return "", 0, user.UnknownUserError(fmt.Sprintf("error looking up uid %q", uid)) -} |