// parseUserGroup parses the User and Group fields of an App and returns its // UID and GID. // The User and Group fields accept several formats: // 1. the hardcoded string "root" // 2. a path // 3. a number // 4. a name in reference to /etc/{group,passwd} in the image // See https://github.com/appc/spec/blob/master/spec/aci.md#image-manifest-schema func parseUserGroup(p *stage1commontypes.Pod, ra *schema.RuntimeApp) (int, int, error) { var uidResolver, gidResolver user.Resolver var uid, gid int var err error root := common.AppRootfsPath(p.Root, ra.Name) uidResolver, err = user.NumericIDs(ra.App.User) if err != nil { uidResolver, err = user.IDsFromStat(root, ra.App.User, &p.UidRange) } if err != nil { uidResolver, err = user.IDsFromEtc(root, ra.App.User, "") } if err != nil { // give up return -1, -1, errwrap.Wrap(fmt.Errorf("invalid user %q", ra.App.User), err) } if uid, _, err = uidResolver.IDs(); err != nil { return -1, -1, errwrap.Wrap(fmt.Errorf("failed to configure user %q", ra.App.User), err) } gidResolver, err = user.NumericIDs(ra.App.Group) if err != nil { gidResolver, err = user.IDsFromStat(root, ra.App.Group, &p.UidRange) } if err != nil { gidResolver, err = user.IDsFromEtc(root, "", ra.App.Group) } if err != nil { // give up return -1, -1, errwrap.Wrap(fmt.Errorf("invalid group %q", ra.App.Group), err) } if _, gid, err = gidResolver.IDs(); err != nil { return -1, -1, errwrap.Wrap(fmt.Errorf("failed to configure group %q", ra.App.Group), err) } return uid, gid, nil }
func TestFromEtc(t *testing.T) { root, err := ioutil.TempDir("", "rkt-TestFromEtc-") if err != nil { panic(err) } defer os.RemoveAll(root) if err := os.Mkdir( filepath.Join(root, "etc"), 0700, ); err != nil { panic(err) } if err := ioutil.WriteFile( filepath.Join(root, "etc/passwd"), []byte(`u1:xxx:1000:100:::`), 0600, ); err != nil { panic(err) } if err := ioutil.WriteFile( filepath.Join(root, "etc/group"), []byte(`g1:xxx:100:u1`), 0600, ); err != nil { panic(err) } for i, tt := range []struct { username, group string // expected err bool uid, gid int }{ { uid: -1, gid: -1, err: false, }, { username: "******", uid: -1, gid: -1, err: true, }, { group: "unknown", uid: -1, gid: -1, err: true, }, { username: "******", uid: 1000, gid: -1, err: false, }, { username: "******", group: "unknown", uid: 1000, gid: -1, err: true, }, { group: "g1", uid: -1, gid: 100, err: false, }, { username: "******", group: "g1", uid: -1, gid: -1, err: true, }, { username: "******", group: "g1", uid: 1000, gid: 100, err: false, }, } { gen, err := user.IDsFromEtc(root, tt.username, tt.group) if err != nil { panic(err) } uid, gid, err := gen.IDs() if err == nil && tt.err { t.Errorf("test %d: expected err but got none", i) } if err != nil && !tt.err { t.Errorf("test %d: expected no err but got one", i) } if uid != tt.uid { t.Errorf("test %d: expected uid %d but got %d", i, tt.uid, uid) } if gid != tt.gid { t.Errorf("test %d: expected gid %d but got %d", i, tt.gid, gid) } } }