Merge pull request #7312 from tianon/update-libcontainer
Bump libcontainer dep
This commit is contained in:
commit
5ba812967e
3 changed files with 0 additions and 351 deletions
|
@ -1 +0,0 @@
|
||||||
Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
|
256
user/user.go
256
user/user.go
|
@ -1,256 +0,0 @@
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
minId = 0
|
|
||||||
maxId = 1<<31 - 1 //for 32-bit systems compatibility
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrRange = fmt.Errorf("Uids and gids must be in range %d-%d", minId, maxId)
|
|
||||||
)
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Name string
|
|
||||||
Pass string
|
|
||||||
Uid int
|
|
||||||
Gid int
|
|
||||||
Gecos string
|
|
||||||
Home string
|
|
||||||
Shell string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Group struct {
|
|
||||||
Name string
|
|
||||||
Pass string
|
|
||||||
Gid int
|
|
||||||
List []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseLine(line string, v ...interface{}) {
|
|
||||||
if line == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(line, ":")
|
|
||||||
for i, p := range parts {
|
|
||||||
if len(v) <= i {
|
|
||||||
// if we have more "parts" than we have places to put them, bail for great "tolerance" of naughty configuration files
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
switch e := v[i].(type) {
|
|
||||||
case *string:
|
|
||||||
// "root", "adm", "/bin/bash"
|
|
||||||
*e = p
|
|
||||||
case *int:
|
|
||||||
// "0", "4", "1000"
|
|
||||||
// ignore string to int conversion errors, for great "tolerance" of naughty configuration files
|
|
||||||
*e, _ = strconv.Atoi(p)
|
|
||||||
case *[]string:
|
|
||||||
// "", "root", "root,adm,daemon"
|
|
||||||
if p != "" {
|
|
||||||
*e = strings.Split(p, ",")
|
|
||||||
} else {
|
|
||||||
*e = []string{}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// panic, because this is a programming/logic error, not a runtime one
|
|
||||||
panic("parseLine expects only pointers! argument " + strconv.Itoa(i) + " is not a pointer!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParsePasswd() ([]*User, error) {
|
|
||||||
return ParsePasswdFilter(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParsePasswdFilter(filter func(*User) bool) ([]*User, error) {
|
|
||||||
f, err := os.Open("/etc/passwd")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
return parsePasswdFile(f, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parsePasswdFile(r io.Reader, filter func(*User) bool) ([]*User, error) {
|
|
||||||
var (
|
|
||||||
s = bufio.NewScanner(r)
|
|
||||||
out = []*User{}
|
|
||||||
)
|
|
||||||
|
|
||||||
for s.Scan() {
|
|
||||||
if err := s.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
text := strings.TrimSpace(s.Text())
|
|
||||||
if text == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// see: man 5 passwd
|
|
||||||
// name:password:UID:GID:GECOS:directory:shell
|
|
||||||
// Name:Pass:Uid:Gid:Gecos:Home:Shell
|
|
||||||
// root:x:0:0:root:/root:/bin/bash
|
|
||||||
// adm:x:3:4:adm:/var/adm:/bin/false
|
|
||||||
p := &User{}
|
|
||||||
parseLine(
|
|
||||||
text,
|
|
||||||
&p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell,
|
|
||||||
)
|
|
||||||
|
|
||||||
if filter == nil || filter(p) {
|
|
||||||
out = append(out, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseGroup() ([]*Group, error) {
|
|
||||||
return ParseGroupFilter(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseGroupFilter(filter func(*Group) bool) ([]*Group, error) {
|
|
||||||
f, err := os.Open("/etc/group")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
return parseGroupFile(f, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseGroupFile(r io.Reader, filter func(*Group) bool) ([]*Group, error) {
|
|
||||||
var (
|
|
||||||
s = bufio.NewScanner(r)
|
|
||||||
out = []*Group{}
|
|
||||||
)
|
|
||||||
|
|
||||||
for s.Scan() {
|
|
||||||
if err := s.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
text := s.Text()
|
|
||||||
if text == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// see: man 5 group
|
|
||||||
// group_name:password:GID:user_list
|
|
||||||
// Name:Pass:Gid:List
|
|
||||||
// root:x:0:root
|
|
||||||
// adm:x:4:root,adm,daemon
|
|
||||||
p := &Group{}
|
|
||||||
parseLine(
|
|
||||||
text,
|
|
||||||
&p.Name, &p.Pass, &p.Gid, &p.List,
|
|
||||||
)
|
|
||||||
|
|
||||||
if filter == nil || filter(p) {
|
|
||||||
out = append(out, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a string like "user", "1000", "user:group", "1000:1000", returns the uid, gid, and list of supplementary group IDs, if possible.
|
|
||||||
func GetUserGroupSupplementary(userSpec string, defaultUid int, defaultGid int) (int, int, []int, error) {
|
|
||||||
var (
|
|
||||||
uid = defaultUid
|
|
||||||
gid = defaultGid
|
|
||||||
suppGids = []int{}
|
|
||||||
|
|
||||||
userArg, groupArg string
|
|
||||||
)
|
|
||||||
|
|
||||||
// allow for userArg to have either "user" syntax, or optionally "user:group" syntax
|
|
||||||
parseLine(userSpec, &userArg, &groupArg)
|
|
||||||
|
|
||||||
users, err := ParsePasswdFilter(func(u *User) bool {
|
|
||||||
if userArg == "" {
|
|
||||||
return u.Uid == uid
|
|
||||||
}
|
|
||||||
return u.Name == userArg || strconv.Itoa(u.Uid) == userArg
|
|
||||||
})
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
if userArg == "" {
|
|
||||||
userArg = strconv.Itoa(uid)
|
|
||||||
}
|
|
||||||
return 0, 0, nil, fmt.Errorf("Unable to find user %v: %v", userArg, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
haveUser := users != nil && len(users) > 0
|
|
||||||
if haveUser {
|
|
||||||
// if we found any user entries that matched our filter, let's take the first one as "correct"
|
|
||||||
uid = users[0].Uid
|
|
||||||
gid = users[0].Gid
|
|
||||||
} else if userArg != "" {
|
|
||||||
// we asked for a user but didn't find them... let's check to see if we wanted a numeric user
|
|
||||||
uid, err = strconv.Atoi(userArg)
|
|
||||||
if err != nil {
|
|
||||||
// not numeric - we have to bail
|
|
||||||
return 0, 0, nil, fmt.Errorf("Unable to find user %v", userArg)
|
|
||||||
}
|
|
||||||
if uid < minId || uid > maxId {
|
|
||||||
return 0, 0, nil, ErrRange
|
|
||||||
}
|
|
||||||
|
|
||||||
// if userArg couldn't be found in /etc/passwd but is numeric, just roll with it - this is legit
|
|
||||||
}
|
|
||||||
|
|
||||||
if groupArg != "" || (haveUser && users[0].Name != "") {
|
|
||||||
groups, err := ParseGroupFilter(func(g *Group) bool {
|
|
||||||
if groupArg != "" {
|
|
||||||
return g.Name == groupArg || strconv.Itoa(g.Gid) == groupArg
|
|
||||||
}
|
|
||||||
for _, u := range g.List {
|
|
||||||
if u == users[0].Name {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
return 0, 0, nil, fmt.Errorf("Unable to find groups for user %v: %v", users[0].Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
haveGroup := groups != nil && len(groups) > 0
|
|
||||||
if groupArg != "" {
|
|
||||||
if haveGroup {
|
|
||||||
// if we found any group entries that matched our filter, let's take the first one as "correct"
|
|
||||||
gid = groups[0].Gid
|
|
||||||
} else {
|
|
||||||
// we asked for a group but didn't find id... let's check to see if we wanted a numeric group
|
|
||||||
gid, err = strconv.Atoi(groupArg)
|
|
||||||
if err != nil {
|
|
||||||
// not numeric - we have to bail
|
|
||||||
return 0, 0, nil, fmt.Errorf("Unable to find group %v", groupArg)
|
|
||||||
}
|
|
||||||
if gid < minId || gid > maxId {
|
|
||||||
return 0, 0, nil, ErrRange
|
|
||||||
}
|
|
||||||
|
|
||||||
// if groupArg couldn't be found in /etc/group but is numeric, just roll with it - this is legit
|
|
||||||
}
|
|
||||||
} else if haveGroup {
|
|
||||||
suppGids = make([]int, len(groups))
|
|
||||||
for i, group := range groups {
|
|
||||||
suppGids[i] = group.Gid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return uid, gid, suppGids, nil
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUserParseLine(t *testing.T) {
|
|
||||||
var (
|
|
||||||
a, b string
|
|
||||||
c []string
|
|
||||||
d int
|
|
||||||
)
|
|
||||||
|
|
||||||
parseLine("", &a, &b)
|
|
||||||
if a != "" || b != "" {
|
|
||||||
t.Fatalf("a and b should be empty ('%v', '%v')", a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
parseLine("a", &a, &b)
|
|
||||||
if a != "a" || b != "" {
|
|
||||||
t.Fatalf("a should be 'a' and b should be empty ('%v', '%v')", a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
parseLine("bad boys:corny cows", &a, &b)
|
|
||||||
if a != "bad boys" || b != "corny cows" {
|
|
||||||
t.Fatalf("a should be 'bad boys' and b should be 'corny cows' ('%v', '%v')", a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
parseLine("", &c)
|
|
||||||
if len(c) != 0 {
|
|
||||||
t.Fatalf("c should be empty (%#v)", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
parseLine("d,e,f:g:h:i,j,k", &c, &a, &b, &c)
|
|
||||||
if a != "g" || b != "h" || len(c) != 3 || c[0] != "i" || c[1] != "j" || c[2] != "k" {
|
|
||||||
t.Fatalf("a should be 'g', b should be 'h', and c should be ['i','j','k'] ('%v', '%v', '%#v')", a, b, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
parseLine("::::::::::", &a, &b, &c)
|
|
||||||
if a != "" || b != "" || len(c) != 0 {
|
|
||||||
t.Fatalf("a, b, and c should all be empty ('%v', '%v', '%#v')", a, b, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
parseLine("not a number", &d)
|
|
||||||
if d != 0 {
|
|
||||||
t.Fatalf("d should be 0 (%v)", d)
|
|
||||||
}
|
|
||||||
|
|
||||||
parseLine("b:12:c", &a, &d, &b)
|
|
||||||
if a != "b" || b != "c" || d != 12 {
|
|
||||||
t.Fatalf("a should be 'b' and b should be 'c', and d should be 12 ('%v', '%v', %v)", a, b, d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserParsePasswd(t *testing.T) {
|
|
||||||
users, err := parsePasswdFile(strings.NewReader(`
|
|
||||||
root:x:0:0:root:/root:/bin/bash
|
|
||||||
adm:x:3:4:adm:/var/adm:/bin/false
|
|
||||||
this is just some garbage data
|
|
||||||
`), nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if len(users) != 3 {
|
|
||||||
t.Fatalf("Expected 3 users, got %v", len(users))
|
|
||||||
}
|
|
||||||
if users[0].Uid != 0 || users[0].Name != "root" {
|
|
||||||
t.Fatalf("Expected users[0] to be 0 - root, got %v - %v", users[0].Uid, users[0].Name)
|
|
||||||
}
|
|
||||||
if users[1].Uid != 3 || users[1].Name != "adm" {
|
|
||||||
t.Fatalf("Expected users[1] to be 3 - adm, got %v - %v", users[1].Uid, users[1].Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserParseGroup(t *testing.T) {
|
|
||||||
groups, err := parseGroupFile(strings.NewReader(`
|
|
||||||
root:x:0:root
|
|
||||||
adm:x:4:root,adm,daemon
|
|
||||||
this is just some garbage data
|
|
||||||
`), nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if len(groups) != 3 {
|
|
||||||
t.Fatalf("Expected 3 groups, got %v", len(groups))
|
|
||||||
}
|
|
||||||
if groups[0].Gid != 0 || groups[0].Name != "root" || len(groups[0].List) != 1 {
|
|
||||||
t.Fatalf("Expected groups[0] to be 0 - root - 1 member, got %v - %v - %v", groups[0].Gid, groups[0].Name, len(groups[0].List))
|
|
||||||
}
|
|
||||||
if groups[1].Gid != 4 || groups[1].Name != "adm" || len(groups[1].List) != 3 {
|
|
||||||
t.Fatalf("Expected groups[1] to be 4 - adm - 3 members, got %v - %v - %v", groups[1].Gid, groups[1].Name, len(groups[1].List))
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue