github.com/clintkitson/docker@v1.9.1/daemon/config_experimental.go (about)

     1  // +build experimental
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/docker/docker/pkg/idtools"
    11  	flag "github.com/docker/docker/pkg/mflag"
    12  	"github.com/opencontainers/runc/libcontainer/user"
    13  )
    14  
    15  func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
    16  	cmd.StringVar(&config.RemappedRoot, []string{"-userns-remap"}, "", usageFn("User/Group setting for user namespaces"))
    17  }
    18  
    19  const (
    20  	defaultIDSpecifier string = "default"
    21  	defaultRemappedID  string = "dockremap"
    22  )
    23  
    24  // Parse the remapped root (user namespace) option, which can be one of:
    25  //   username            - valid username from /etc/passwd
    26  //   username:groupname  - valid username; valid groupname from /etc/group
    27  //   uid                 - 32-bit unsigned int valid Linux UID value
    28  //   uid:gid             - uid value; 32-bit unsigned int Linux GID value
    29  //
    30  //  If no groupname is specified, and a username is specified, an attempt
    31  //  will be made to lookup a gid for that username as a groupname
    32  //
    33  //  If names are used, they are verified to exist in passwd/group
    34  func parseRemappedRoot(usergrp string) (string, string, error) {
    35  
    36  	var (
    37  		userID, groupID     int
    38  		username, groupname string
    39  	)
    40  
    41  	idparts := strings.Split(usergrp, ":")
    42  	if len(idparts) > 2 {
    43  		return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp)
    44  	}
    45  
    46  	if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil {
    47  		// must be a uid; take it as valid
    48  		userID = int(uid)
    49  		luser, err := user.LookupUid(userID)
    50  		if err != nil {
    51  			return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err)
    52  		}
    53  		username = luser.Name
    54  		if len(idparts) == 1 {
    55  			// if the uid was numeric and no gid was specified, take the uid as the gid
    56  			groupID = userID
    57  			lgrp, err := user.LookupGid(groupID)
    58  			if err != nil {
    59  				return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err)
    60  			}
    61  			groupname = lgrp.Name
    62  		}
    63  	} else {
    64  		lookupName := idparts[0]
    65  		// special case: if the user specified "default", they want Docker to create or
    66  		// use (after creation) the "dockremap" user/group for root remapping
    67  		if lookupName == defaultIDSpecifier {
    68  			lookupName = defaultRemappedID
    69  		}
    70  		luser, err := user.LookupUser(lookupName)
    71  		if err != nil && idparts[0] != defaultIDSpecifier {
    72  			// error if the name requested isn't the special "dockremap" ID
    73  			return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err)
    74  		} else if err != nil {
    75  			// special case-- if the username == "default", then we have been asked
    76  			// to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid}
    77  			// ranges will be used for the user and group mappings in user namespaced containers
    78  			_, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID)
    79  			if err == nil {
    80  				return defaultRemappedID, defaultRemappedID, nil
    81  			}
    82  			return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err)
    83  		}
    84  		userID = luser.Uid
    85  		username = luser.Name
    86  		if len(idparts) == 1 {
    87  			// we only have a string username, and no group specified; look up gid from username as group
    88  			group, err := user.LookupGroup(lookupName)
    89  			if err != nil {
    90  				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err)
    91  			}
    92  			groupID = group.Gid
    93  			groupname = group.Name
    94  		}
    95  	}
    96  
    97  	if len(idparts) == 2 {
    98  		// groupname or gid is separately specified and must be resolved
    99  		// to a unsigned 32-bit gid
   100  		if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil {
   101  			// must be a gid, take it as valid
   102  			groupID = int(gid)
   103  			lgrp, err := user.LookupGid(groupID)
   104  			if err != nil {
   105  				return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err)
   106  			}
   107  			groupname = lgrp.Name
   108  		} else {
   109  			// not a number; attempt a lookup
   110  			group, err := user.LookupGroup(idparts[1])
   111  			if err != nil {
   112  				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", idparts[1], err)
   113  			}
   114  			groupID = group.Gid
   115  			groupname = idparts[1]
   116  		}
   117  	}
   118  	return username, groupname, nil
   119  }