Select Git revision
-
installed tmux & screen. updated mergetb & mergexp library. /created.txt timestamps both base and jupyter container build time.
installed tmux & screen. updated mergetb & mergexp library. /created.txt timestamps both base and jupyter container build time.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
group.go 4.31 KiB
package workspace
import (
"fmt"
"io/ioutil"
"os"
"sort"
"strconv"
"strings"
log "github.com/sirupsen/logrus"
)
// Group describes an /etc/group style file.
type Group struct {
File *SharedFile
Entries map[string]*GroupEntry
}
// GroupEntry describes an entry in a group file.
type GroupEntry struct {
Name string
Id int
Users []string
}
// OpenGroup - open the group file.
func OpenGroup(file string) (*Group, error) {
sf, err := SharedOpen(file)
if err != nil {
return nil, err
}
group := &Group{
File: sf,
Entries: make(map[string]*GroupEntry),
}
err = group.read()
if err != nil {
group.Close()
return nil, err
}
return group, nil
}
func (g *Group) read() error {
if _, err := os.Stat(g.File.Path); !os.IsNotExist(err) {
src, err := ioutil.ReadFile(g.File.Path)
if err != nil {
return fmt.Errorf("could not read %s", err)
}
lines := strings.Split(string(src), "\n")
for _, l := range lines {
e := readGroupEntry(l)
if e == nil {
continue
}
g.Entries[e.Name] = e
}
}
return nil
}
func readGroupEntry(line string) *GroupEntry {
// example entries:
// adm:x:4:syslog,glawler
// root:x:0:
if line == "" {
return nil
}
parts := strings.Split(line, ":")
if len(parts) < 3 {
log.WithFields(log.Fields{"entry": line}).Warn("invalid group entry")
return nil
}
id, err := strconv.Atoi(parts[2])
if err != nil {
log.WithFields(log.Fields{"entry": line}).Warn("invalid group id")
return nil
}
ge := &GroupEntry{
Name: parts[0],
Id: id,
}
if parts[3] != "" {
for _, u := range strings.Split(parts[3], ",") {
ge.Users = append(ge.Users, u)
}
}
return ge
}
func (e *GroupEntry) Write() string {
return fmt.Sprintf("%s:x:%d:%s", e.Name, e.Id, strings.Join(e.Users, ","))
}
func (e *GroupEntry) userExists(user string) bool {
for _, u := range e.Users {
if u == user {
return true
}
}
return false
}
// Merge two group entries. The passed in entry takes precedence if there is a clash. Names must match though.
func (ge *GroupEntry) Merge(b *GroupEntry) error {
if ge.Name != b.Name {
return fmt.Errorf("bad group entry merge")
}
// merge users, cutting out duplicates
for _, u := range b.Users {
if !ge.userExists(u) {
ge.Users = append(ge.Users, u)
}
}
return nil
}
// Merge two Groups. The passed in takes precedence when there is a clash.
func (g *Group) Merge(other *Group) error {
for _, oe := range other.Entries {
if ge, ok := g.Entries[oe.Name]; ok { // merge dup entry
err := ge.Merge(oe)
if err != nil {
return err
}
} else {
g.Entries[oe.Name] = oe
}
}
return nil
}
func (g *Group) Write() error {
src := g.String()
return ioutil.WriteFile(g.File.Path, []byte(src), 0644)
}
// AddUser adds the given user to an exising group.
func (g *Group) AddUser(group, user string) error {
entry, ok := g.Entries[group]
if !ok {
return fmt.Errorf("cannot add user %s: no such group %s", user, group)
}
// add the user if it doesn't already exist.
if !entry.userExists(user) {
entry.Users = append(entry.Users, user)
}
return nil
}
// GetEntry retrives a group entry by name.
func (g *Group) GetEntry(name string) (*GroupEntry, error) {
entry, ok := g.Entries[name]
if !ok {
return nil, fmt.Errorf("no such group: %s", name)
}
return entry, nil
}
// AddEntry will add or overwrite an existing entry to the Group
func (g *Group) AddEntry(e *GroupEntry) {
g.Entries[e.Name] = e
}
func (g *Group) String() string {
var entries []*GroupEntry
for _, e := range g.Entries {
entries = append(entries, e)
}
sort.Slice(entries, func(i, j int) bool {
return entries[i].Id < entries[j].Id
})
var src string
for _, e := range entries {
src += e.Write() + "\n"
}
return src
}
// Close - close the group file.
func (g *Group) Close() {
g.File.Close()
}
// AddAllToGroup adds all accounts in the passwd given to the group given in the etc/group file specified.
func (g *Group) AddAllToGroup(group, passwdpath string) error {
if _, ok := g.Entries[group]; !ok {
return fmt.Errorf("non existent group")
}
p, err := OpenPasswd(passwdpath)
if err != nil {
return fmt.Errorf("bad passwd path")
}
defer p.Close()
for _, pe := range p.Entries {
err = g.AddUser(group, pe.Username)
if err != nil {
return fmt.Errorf("error adding user %s to group %s", pe.Username, group)
}
}
return nil
}