Skip to content

Commit

Permalink
Merge pull request #7 from getsolus/6-enable-support-to-retroactively…
Browse files Browse the repository at this point in the history
…-add-users-to-etcsubuid-and-etcsubgid-files

migrations: Add support for adding subuids and subgids to users
  • Loading branch information
ermo authored Jul 2, 2024
2 parents 3b7f370 + 27e7f19 commit a99a922
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 2 deletions.
43 changes: 43 additions & 0 deletions core/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,44 @@ func (c *Context) FilterUsers(filters ...string) (filtered []User) {
return filtered
}

// GetRootUser gets the root user
func (c *Context) GetRootUser() User {
for _, user := range c.users {
if user.IsRoot {
return user
}
}

return User{}
}

// GetUsersInGroup returns all users that are in the given group
func (c *Context) GetUsersInGroup(group string) (users []User) {
for _, user := range c.users {
if c.UserInGroup(user, group) {
users = append(users, user)
}
}

return
}

// AddSubUids adds a range of subids for a user. Returns an error if something went wrong
func (c *Context) AddSubUids(user *User, rangeStart, rangeEnd int) error {
idRange := fmt.Sprintf("%d-%d", rangeStart, rangeEnd)
cmd := exec.Command("usermod", "--add-subuids", idRange, user.Name)

return cmd.Run()
}

// AddSubGids adds a range of subids for a user. Returns an error if something went wrong
func (c *Context) AddSubGids(user *User, rangeStart, rangeEnd int) error {
idRange := fmt.Sprintf("%d-%d", rangeStart, rangeEnd)
cmd := exec.Command("usermod", "--add-subgids", idRange, user.Name)

return cmd.Run()
}

// AddToGroup adds a User to a preexisting group. Returns whether or not the modification ran, along with an error in
// case something went wrong
func (c *Context) AddToGroup(user *User, group string) (ran bool, err error) {
Expand Down Expand Up @@ -186,6 +224,11 @@ func (c *Context) UpdateGroupID(name string, id string) error {
return nil
}

// UserInGroup returns whether a user is in a particular group
func (c *Context) UserInGroup(user User, group string) bool {
return contains(user.Groups, group)
}

func (c *Context) populateGroups() (err error) {
c.groups = make([]gouser.Group, 0)

Expand Down
87 changes: 85 additions & 2 deletions core/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@
package core

import (
"errors"
"fmt"
"github.com/BurntSushi/toml"
"github.com/DataDrake/waterlog"
"io/ioutil"
"os"
gouser "os/user"
"path/filepath"
"strconv"

"github.com/BurntSushi/toml"
"github.com/DataDrake/waterlog"
)

// Migration contains the information about a migration, including where it is on the system and its requested system modifications
Expand All @@ -30,13 +33,21 @@ type Migration struct {
Path string

Description string `toml:"description"`
AddSubIds []*AddSubIds `toml:"add-subids"`
UpdateUsers []*UpdateUsers `toml:"users-update"`
UpdateGroup []*UpdateGroup `toml:"group-update"`
RemoveUsers []*RemoveUsers `toml:"users-remove"`
RemoveGroup []*RemoveGroup `toml:"group-delete"`
DeleteUsers []*DeleteUsers `toml:"users-delete"`
}

// AddSubIds is a type of modification that adds subuids and subgids to a specific set of users
type AddSubIds struct {
GroupName string `toml:"group"`
RangeStart int `toml:"range-start"`
RangeEnd int `toml:"range-end"`
}

// UpdateUsers is a type of modification that adds a group to a specific set of users
type UpdateUsers struct {
UserFilters []string `toml:"only"`
Expand Down Expand Up @@ -133,6 +144,9 @@ func (m *Migration) Validate() error {
// Run applies the modifications contained in a migration
func (m *Migration) Run(context *Context) {
waterlog.Debugf("Running migration %s...\n", m.Name)
for _, task := range m.AddSubIds {
m.addSubIds(context, task)
}
for _, task := range m.UpdateUsers {
m.updateUsers(context, task)
}
Expand All @@ -150,6 +164,75 @@ func (m *Migration) Run(context *Context) {
}
}

func (m *Migration) addSubIds(context *Context, task *AddSubIds) {
users := context.GetUsersInGroup(task.GroupName)
users = append(users, context.GetRootUser())

m.createSubUidFile(context, task, users)
m.createSubGidFile(context, task, users)
}

func createFileIfNotExists(path string) (bool, error) {
fh, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)

if err != nil {
if errors.Is(err, os.ErrExist) {
waterlog.Debugf("\t%s already exists, skipping", path)
// The file already existing isn't an error mode for us,
// so don't propagate the error.
return false, nil
}

return false, err
}

fh.Close()

return true, nil
}

func (m *Migration) createSubUidFile(context *Context, task *AddSubIds, users []User) {
created, err := createFileIfNotExists("/etc/subuid")

if !created {
if err != nil {
waterlog.Warnf("\tUnable to create /etc/subuid due to error: %s\n", err)
}

return
}

for _, user := range users {
if err := context.AddSubUids(&user, task.RangeStart, task.RangeEnd); err != nil {
waterlog.Warnf("\tFailed to add subuids to user %s due to error: %s\n", user.Name, err)
return
}

waterlog.Debugf("\tSuccessfully added subuids to user %s\n", user.Name)
}
}

func (m *Migration) createSubGidFile(context *Context, task *AddSubIds, users []User) {
created, err := createFileIfNotExists("/etc/subgid")

if !created {
if err != nil {
waterlog.Warnf("\tUnable to create /etc/subgid due to error: %s\n", err)
}

return
}

for _, user := range users {
if err := context.AddSubGids(&user, task.RangeStart, task.RangeEnd); err != nil {
waterlog.Warnf("\tFailed to add subgids to user %s due to error: %s\n", user.Name, err)
return
}

waterlog.Debugf("\tSuccessfully added subgids to user %s\n", user.Name)
}
}

func (m *Migration) updateUsers(context *Context, task *UpdateUsers) {
filtered := context.FilterUsers(task.UserFilters...)

Expand Down

0 comments on commit a99a922

Please sign in to comment.