Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Feb 24, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## vUNRELEASED

#### New features and UX changes

- Add support for non-numerical UID/GID as specified in the appc spec ([#2159](https://github.com/coreos/rkt/pull/2159)).

#### Bug fixes
- Socket activation was not working if the port on the host is different from the app port as set in the image manifest ([#2137](https://github.com/coreos/rkt/pull/2137)).
- Fix a bug when fetching images from private repositories in the official Docker registry ([#2197](https://github.com/coreos/rkt/pull/2197)).
Expand Down
48 changes: 33 additions & 15 deletions pkg/group/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package group

import (
"bufio"
"errors"
"fmt"
"io"
"os"
Expand All @@ -37,12 +38,12 @@ type Group struct {
Users []string
}

// LookupGid reads the group file and returns the gid of the group
// LookupGid reads the group file specified by groupFile, and returns the gid of the group
// specified by groupName.
func LookupGid(groupName string) (gid int, err error) {
groups, err := parseGroupFile(groupFilePath)
func LookupGidFromFile(groupName, groupFile string) (gid int, err error) {
groups, err := parseGroupFile(groupFile)
if err != nil {
return -1, errwrap.Wrap(fmt.Errorf("error parsing %q file", groupFilePath), err)
return -1, errwrap.Wrap(fmt.Errorf("error parsing %q file", groupFile), err)
}

group, ok := groups[groupName]
Expand All @@ -53,7 +54,13 @@ func LookupGid(groupName string) (gid int, err error) {
return group.Gid, nil
}

func parseGroupFile(path string) (group map[string]Group, err error) {
// LookupGid reads the group file and returns the gid of the group
// specified by groupName.
func LookupGid(groupName string) (gid int, err error) {
return LookupGidFromFile(groupName, groupFilePath)
}

func parseGroupFile(path string) (group map[string]*Group, err error) {
groupFile, err := os.Open(path)
if err != nil {
return nil, err
Expand All @@ -63,9 +70,9 @@ func parseGroupFile(path string) (group map[string]Group, err error) {
return parseGroups(groupFile)
}

func parseGroups(r io.Reader) (group map[string]Group, err error) {
func parseGroups(r io.Reader) (group map[string]*Group, err error) {
s := bufio.NewScanner(r)
out := make(map[string]Group)
out := make(map[string]*Group)

for s.Scan() {
if err := s.Err(); err != nil {
Expand All @@ -77,40 +84,51 @@ func parseGroups(r io.Reader) (group map[string]Group, err error) {
continue
}

p := Group{}
parseGroupLine(text, &p)
p, err := parseGroupLine(text)
if err != nil {
return nil, errwrap.Wrap(errors.New("error parsing line"), err)
}

out[p.Name] = p
}

return out, nil
}

func parseGroupLine(line string, group *Group) {
func parseGroupLine(line string) (*Group, error) {
const (
NameIdx = iota
PassIdx
GidIdx
UsersIdx
)
var err error

if line == "" {
return
return nil, errors.New("cannot parse empty line")
}

splits := strings.Split(line, ":")
if len(splits) < 4 {
return
return nil, fmt.Errorf("expected at least 4 fields, got %d", len(splits))
}

group := &Group{
Name: splits[NameIdx],
Pass: splits[PassIdx],
}

group.Name = splits[NameIdx]
group.Pass = splits[PassIdx]
group.Gid, _ = strconv.Atoi(splits[GidIdx])
group.Gid, err = strconv.Atoi(splits[GidIdx])
if err != nil {
return nil, errwrap.Wrap(errors.New("unable to parse gid"), err)
}

u := splits[UsersIdx]
if u != "" {
group.Users = strings.Split(u, ",")
} else {
group.Users = []string{}
}

return group, nil
}
29 changes: 20 additions & 9 deletions pkg/group/group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,49 +21,60 @@ import (

func TestParseGroupLine(t *testing.T) {
tests := []struct {
line string
groupLine Group
line string
groupLine *Group
shouldSucceed bool
}{
{
"ftp:x:1:",
Group{
&Group{
"ftp",
"x",
1,
[]string{},
},
true,
},
{
"u1:xxx:12:wheel,users",
Group{
&Group{
"u1",
"xxx",
12,
[]string{"wheel", "users"},
},
true,
},
{
"uerr:x:",
Group{},
nil,
false,
},
{
"",
Group{},
nil,
false,
},
{
"u1:xxx:12:wheel,users:extra:stuff",
Group{
&Group{
"u1",
"xxx",
12,
[]string{"wheel", "users"},
},
true,
},
}

for i, tt := range tests {
g := Group{}
parseGroupLine(tt.line, &g)
g, err := parseGroupLine(tt.line)
if err != nil {
if tt.shouldSucceed {
t.Errorf("#%d: parsing line %q failed unexpectedly", i, tt.line)
}
continue
}
if !reflect.DeepEqual(g, tt.groupLine) {
t.Errorf("#%d: got group %v, want group %v", i, g, tt.groupLine)
}
Expand Down
140 changes: 140 additions & 0 deletions pkg/passwd/passwd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2016 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package passwd

import (
"bufio"
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"

"github.com/hashicorp/errwrap"
)

const (
passwdFilePath = "/etc/passwd"
)

// User represents an entry in the passwd file.
type User struct {
Name string
Pass string
Uid int
Gid int
Comment string
Home string
Interpreter string
}

// LookupUidFromFile reads the passwd file specified by passwdFile, and returns the
// uid of the user specified by userName.
func LookupUidFromFile(userName, passwdFile string) (uid int, err error) {
users, err := parsePasswdFile(passwdFile)
if err != nil {
return -1, errwrap.Wrap(fmt.Errorf("error parsing %q file", passwdFile), err)
}

user, ok := users[userName]
if !ok {
return -1, fmt.Errorf("%q user not found", userName)
}

return user.Uid, nil
}

// LookupUid reads the passwd file and returns the uid of the user
// specified by userName.
func LookupUid(userName string) (uid int, err error) {
return LookupUidFromFile(userName, passwdFilePath)
}

func parsePasswdFile(path string) (user map[string]*User, err error) {
passwdFile, err := os.Open(path)
if err != nil {
return nil, err
}
defer passwdFile.Close()

return parseUsers(passwdFile)
}

func parseUsers(r io.Reader) (user map[string]*User, err error) {
s := bufio.NewScanner(r)
out := make(map[string]*User)

for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}

text := s.Text()
if text == "" {
continue
}

p, err := parsePasswdLine(text)
if err != nil {
return nil, errwrap.Wrap(errors.New("error parsing line"), err)
}

out[p.Name] = p
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should you test if parsePasswdLine really returned a user? p.Name can be "" if a line is not parsed correctly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that pkg/group/group.go has the same pattern.

/cc @krnowak

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't write the /etc/groups parser, but I don't like this pattern at all. It should just return a pointer to user struct and also it should return an error if parsing the file failed (in case of invalid number of fields). So a prototype like func parsePasswdLine(line text) (*User, error) should be used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git blame said @krnowak so I thought you wrote it.

Should "pkg/group" be changed first to be consistent? But @marineam might be working on it via #2105.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, because I moved that from common to pkg/group. And @marineam is probably working on a different code anyway.

}

return out, nil
}

func parsePasswdLine(line string) (*User, error) {
const (
NameIdx = iota
PassIdx
UidIdx
GidIdx
CommentIdx
HomeIdx
InterpreterIdx
)
var err error

if line == "" {
return nil, errors.New("cannot parse empty line")
}

splits := strings.Split(line, ":")
if len(splits) < 7 {
return nil, fmt.Errorf("expected at least 7 fields, got %d", len(splits))
}

user := &User{
Name: splits[NameIdx],
Pass: splits[PassIdx],
Comment: splits[CommentIdx],
Home: splits[HomeIdx],
Interpreter: splits[InterpreterIdx],
}

user.Uid, err = strconv.Atoi(splits[UidIdx])
if err != nil {
return nil, errwrap.Wrap(errors.New("unable to parse uid"), err)
}
user.Gid, err = strconv.Atoi(splits[GidIdx])
if err != nil {
return nil, errwrap.Wrap(errors.New("unable to parse gid"), err)
}

return user, nil
}
Loading