github.com/rootless-containers/rootlesskit/v2@v2.3.4/pkg/parent/idtools/idtools.go (about)

     1  // Package idtools is forked from https://github.com/moby/moby/tree/298ba5b13150bfffe8414922a951a7a793276d31/pkg/idtools
     2  package idtools
     3  
     4  import (
     5  	"bufio"
     6  	"fmt"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  )
    11  
    12  type SubIDRange struct {
    13  	Start  int
    14  	Length int
    15  }
    16  
    17  const (
    18  	subuidFileName = "/etc/subuid"
    19  	subgidFileName = "/etc/subgid"
    20  )
    21  
    22  func GetSubIDRanges(uid int, username string) ([]SubIDRange, []SubIDRange, error) {
    23  	subuidRanges, err := parseSubuid(uid, username)
    24  	if err != nil {
    25  		return nil, nil, err
    26  	}
    27  	subgidRanges, err := parseSubgid(uid, username)
    28  	if err != nil {
    29  		return nil, nil, err
    30  	}
    31  	if len(subuidRanges) == 0 {
    32  		return nil, nil, fmt.Errorf("No subuid ranges found for user %d (%q)", uid, username)
    33  	}
    34  	if len(subgidRanges) == 0 {
    35  		return nil, nil, fmt.Errorf("No subgid ranges found for user %d (%q)", uid, username)
    36  	}
    37  	return subuidRanges, subgidRanges, nil
    38  }
    39  
    40  func parseSubuid(uid int, username string) ([]SubIDRange, error) {
    41  	return parseSubidFile(subuidFileName, uid, username)
    42  }
    43  
    44  func parseSubgid(uid int, username string) ([]SubIDRange, error) {
    45  	return parseSubidFile(subgidFileName, uid, username)
    46  }
    47  
    48  // parseSubidFile will read the appropriate file (/etc/subuid or /etc/subgid)
    49  // and return all found ranges for a specified user. username is optional.
    50  func parseSubidFile(path string, uid int, username string) ([]SubIDRange, error) {
    51  	uidS := strconv.Itoa(uid)
    52  	var rangeList []SubIDRange
    53  
    54  	subidFile, err := os.Open(path)
    55  	if err != nil {
    56  		return rangeList, err
    57  	}
    58  	defer subidFile.Close()
    59  
    60  	s := bufio.NewScanner(subidFile)
    61  	for s.Scan() {
    62  		text := strings.TrimSpace(s.Text())
    63  		if text == "" || strings.HasPrefix(text, "#") {
    64  			continue
    65  		}
    66  		parts := strings.Split(text, ":")
    67  		if len(parts) != 3 {
    68  			return rangeList, fmt.Errorf("Cannot parse subuid/gid information: Format not correct for %s file", path)
    69  		}
    70  		if parts[0] == uidS || (username != "" && parts[0] == username) {
    71  			startid, err := strconv.Atoi(parts[1])
    72  			if err != nil {
    73  				return rangeList, fmt.Errorf("String to int conversion failed during subuid/gid parsing of %s: %v", path, err)
    74  			}
    75  			length, err := strconv.Atoi(parts[2])
    76  			if err != nil {
    77  				return rangeList, fmt.Errorf("String to int conversion failed during subuid/gid parsing of %s: %v", path, err)
    78  			}
    79  			rangeList = append(rangeList, SubIDRange{startid, length})
    80  		}
    81  	}
    82  	return rangeList, s.Err()
    83  }