@@ -16,7 +16,7 @@ import (
1616
1717type User struct {
1818 User string
19- Uid uint32 //nolint:revive
19+ Uid uint32
2020 Group string
2121 Gid uint32
2222 Home string
@@ -30,6 +30,14 @@ type Group struct {
3030var users map [string ]User
3131var groups map [string ]Group
3232
33+ // regexUsername matches user and group names to be valid for `useradd`.
34+ // `useradd` allows names with a trailing '$', but it feels prudent to map those
35+ // names to the fallback user as well, so the regex does not allow them.
36+ var regexUsername = regexp .MustCompile ("^[a-z_][a-z0-9_-]*$" )
37+
38+ // regexPath detects valid Linux path.
39+ var regexPath = regexp .MustCompile ("^[/a-zA-Z0-9_-]+$" )
40+
3341func LookupUser (name string ) (User , error ) {
3442 if users == nil {
3543 users = make (map [string ]User )
@@ -43,15 +51,15 @@ func LookupUser(name string) (User, error) {
4351 if err != nil {
4452 return User {}, err
4553 }
46- uid , err := strconv . ParseUint (u .Uid , 10 , 32 )
54+ uid , err := parseUidGid (u .Uid )
4755 if err != nil {
4856 return User {}, err
4957 }
50- gid , err := strconv . ParseUint (u .Gid , 10 , 32 )
58+ gid , err := parseUidGid (u .Gid )
5159 if err != nil {
5260 return User {}, err
5361 }
54- users [name ] = User {User : u .Username , Uid : uint32 ( uid ) , Group : g .Name , Gid : uint32 ( gid ) , Home : u .HomeDir }
62+ users [name ] = User {User : u .Username , Uid : uid , Group : g .Name , Gid : gid , Home : u .HomeDir }
5563 }
5664 return users [name ], nil
5765}
@@ -65,18 +73,18 @@ func LookupGroup(name string) (Group, error) {
6573 if err != nil {
6674 return Group {}, err
6775 }
68- gid , err := strconv . ParseUint (g .Gid , 10 , 32 )
76+ gid , err := parseUidGid (g .Gid )
6977 if err != nil {
7078 return Group {}, err
7179 }
72- groups [name ] = Group {Name : g .Name , Gid : uint32 ( gid ) }
80+ groups [name ] = Group {Name : g .Name , Gid : gid }
7381 }
7482 return groups [name ], nil
7583}
7684
7785const (
7886 fallbackUser = "lima"
79- fallbackUid = 1000 //nolint:revive
87+ fallbackUid = 1000
8088 fallbackGid = 1000
8189)
8290
@@ -101,12 +109,9 @@ func LimaUser(warn bool) (*user.User, error) {
101109 cache .Do (func () {
102110 cache .u , cache .err = user .Current ()
103111 if cache .err == nil {
104- // `useradd` only allows user and group names matching the following pattern:
105- // (it allows a trailing '$', but it feels prudent to map those to the fallback user as well)
106- validName := "^[a-z_][a-z0-9_-]*$"
107- if ! regexp .MustCompile (validName ).Match ([]byte (cache .u .Username )) {
112+ if ! regexUsername .MatchString (cache .u .Username ) {
108113 warning := fmt .Sprintf ("local user %q is not a valid Linux username (must match %q); using %q username instead" ,
109- cache .u .Username , validName , fallbackUser )
114+ cache .u .Username , regexUsername . String () , fallbackUser )
110115 cache .warnings = append (cache .warnings , warning )
111116 cache .u .Username = fallbackUser
112117 }
@@ -115,29 +120,29 @@ func LimaUser(warn bool) (*user.User, error) {
115120 if err != nil {
116121 logrus .Debug (err )
117122 }
118- uid , err := strconv . ParseUint (idu , 10 , 32 )
123+ uid , err := parseUidGid (idu )
119124 if err != nil {
120125 uid = fallbackUid
121126 }
122- if ! regexp . MustCompile ( "^[0-9]+$" ). Match ([] byte ( cache .u .Uid )) {
127+ if _ , err := parseUidGid ( cache .u .Uid ); err != nil {
123128 warning := fmt .Sprintf ("local uid %q is not a valid Linux uid (must be integer); using %d uid instead" ,
124129 cache .u .Uid , uid )
125130 cache .warnings = append (cache .warnings , warning )
126- cache .u .Uid = fmt . Sprintf ( "%d" , uid )
131+ cache .u .Uid = formatUidGid ( uid )
127132 }
128133 idg , err := call ([]string {"id" , "-g" })
129134 if err != nil {
130135 logrus .Debug (err )
131136 }
132- gid , err := strconv . ParseUint (idg , 10 , 32 )
137+ gid , err := parseUidGid (idg )
133138 if err != nil {
134139 gid = fallbackGid
135140 }
136- if ! regexp . MustCompile ( "^[0-9]+$" ). Match ([] byte ( cache .u .Gid )) {
141+ if _ , err := parseUidGid ( cache .u .Gid ); err != nil {
137142 warning := fmt .Sprintf ("local gid %q is not a valid Linux gid (must be integer); using %d gid instead" ,
138143 cache .u .Gid , gid )
139144 cache .warnings = append (cache .warnings , warning )
140- cache .u .Gid = fmt . Sprintf ( "%d" , gid )
145+ cache .u .Gid = formatUidGid ( gid )
141146 }
142147 home , err := call ([]string {"cygpath" , cache .u .HomeDir })
143148 if err != nil {
@@ -150,10 +155,9 @@ func LimaUser(warn bool) (*user.User, error) {
150155 prefix := strings .ToLower (fmt .Sprintf ("/%c" , drive [0 ]))
151156 home = strings .Replace (home , drive , prefix , 1 )
152157 }
153- validPath := "^[/a-zA-Z0-9_-]+$"
154- if ! regexp .MustCompile (validPath ).Match ([]byte (cache .u .HomeDir )) {
158+ if ! regexPath .MatchString (cache .u .HomeDir ) {
155159 warning := fmt .Sprintf ("local home %q is not a valid Linux path (must match %q); using %q home instead" ,
156- cache .u .HomeDir , validPath , home )
160+ cache .u .HomeDir , regexPath . String () , home )
157161 cache .warnings = append (cache .warnings , warning )
158162 cache .u .HomeDir = home
159163 }
@@ -167,3 +171,17 @@ func LimaUser(warn bool) (*user.User, error) {
167171 }
168172 return cache .u , cache .err
169173}
174+
175+ // parseUidGid converts string value to Linux uid or gid.
176+ func parseUidGid (uidOrGid string ) (uint32 , error ) {
177+ res , err := strconv .ParseUint (uidOrGid , 10 , 32 )
178+ if err != nil {
179+ return 0 , err
180+ }
181+ return uint32 (res ), nil
182+ }
183+
184+ // formatUidGid converts uid or gid to string value.
185+ func formatUidGid (uidOrGid uint32 ) string {
186+ return strconv .FormatUint (uint64 (uidOrGid ), 10 )
187+ }
0 commit comments