kops/upup/pkg/fi/users.go

170 lines
3.7 KiB
Go

/*
Copyright 2019 The Kubernetes 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 fi
import (
"fmt"
"os"
"strconv"
"strings"
"k8s.io/klog/v2"
)
// This file parses /etc/passwd and /etc/group to get information about users & groups
// Go has built-in user functionality, and group functionality is merged but not yet released
// TODO: Replace this file with e.g. user.LookupGroup once 42f07ff2679d38a03522db3ccd488f4cc230c8c2 lands in go 1.7
type User struct {
Name string
Uid int
Gid int
Comment string
Home string
Shell string
}
func parseUsers() (map[string]*User, error) {
users := make(map[string]*User)
path := "/etc/passwd"
b, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("error reading user file %q", path)
}
for _, line := range strings.Split(string(b), "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
tokens := strings.Split(line, ":")
if len(tokens) < 7 {
klog.Warningf("Ignoring malformed /etc/passwd line (too few tokens): %q\n", line)
continue
}
uid, err := strconv.Atoi(tokens[2])
if err != nil {
klog.Warningf("Ignoring malformed /etc/passwd line (bad uid): %q", line)
continue
}
gid, err := strconv.Atoi(tokens[3])
if err != nil {
klog.Warningf("Ignoring malformed /etc/passwd line (bad gid): %q", line)
continue
}
u := &User{
Name: tokens[0],
// Password
Uid: uid,
Gid: gid,
Comment: tokens[4],
Home: tokens[5],
Shell: tokens[6],
}
users[u.Name] = u
}
return users, nil
}
func LookupUser(name string) (*User, error) {
users, err := parseUsers()
if err != nil {
return nil, fmt.Errorf("error reading users: %v", err)
}
return users[name], nil
}
func LookupUserByID(uid int) (*User, error) {
users, err := parseUsers()
if err != nil {
return nil, fmt.Errorf("error reading users: %v", err)
}
for _, v := range users {
if v.Uid == uid {
return v, nil
}
}
return nil, nil
}
type Group struct {
Name string
Gid int
// Members []string
}
func parseGroups() (map[string]*Group, error) {
groups := make(map[string]*Group)
path := "/etc/group"
b, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("error reading group file %q", path)
}
for _, line := range strings.Split(string(b), "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
tokens := strings.Split(line, ":")
if len(tokens) < 4 {
klog.Warningf("Ignoring malformed /etc/group line (too few tokens): %q", line)
continue
}
gid, err := strconv.Atoi(tokens[2])
if err != nil {
klog.Warningf("Ignoring malformed /etc/group line (bad gid): %q", line)
continue
}
g := &Group{
Name: tokens[0],
// Password: tokens[1]
Gid: gid,
// Members: strings.Split(tokens[3], ",")
}
groups[g.Name] = g
}
return groups, nil
}
func LookupGroup(name string) (*Group, error) {
groups, err := parseGroups()
if err != nil {
return nil, fmt.Errorf("error reading groups: %v", err)
}
return groups[name], nil
}
func LookupGroupByID(gid int) (*Group, error) {
users, err := parseGroups()
if err != nil {
return nil, fmt.Errorf("error reading groups: %v", err)
}
for _, v := range users {
if v.Gid == gid {
return v, nil
}
}
return nil, nil
}