Skip to content

Commit fbb4d5d

Browse files
Merge pull request #21692 from Luap99/machine-cleanup
machine init: validate machine name and username
2 parents 3b34232 + 2846027 commit fbb4d5d

6 files changed

Lines changed: 141 additions & 118 deletions

File tree

cmd/podman/machine/init.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/containers/common/pkg/completion"
1010
"github.com/containers/podman/v5/cmd/podman/registry"
11+
ldefine "github.com/containers/podman/v5/libpod/define"
1112
"github.com/containers/podman/v5/libpod/events"
1213
"github.com/containers/podman/v5/pkg/machine"
1314
"github.com/containers/podman/v5/pkg/machine/define"
@@ -136,13 +137,21 @@ func initMachine(cmd *cobra.Command, args []string) error {
136137
return fmt.Errorf("machine name %q must be %d characters or less", args[0], maxMachineNameSize)
137138
}
138139
initOpts.Name = args[0]
140+
141+
if !ldefine.NameRegex.MatchString(initOpts.Name) {
142+
return fmt.Errorf("invalid name %q: %w", initOpts.Name, ldefine.RegexError)
143+
}
139144
}
140145

141146
// The vmtype names need to be reserved and cannot be used for podman machine names
142147
if _, err := define.ParseVMType(initOpts.Name, define.UnknownVirt); err == nil {
143148
return fmt.Errorf("cannot use %q for a machine name", initOpts.Name)
144149
}
145150

151+
if !ldefine.NameRegex.MatchString(initOpts.Username) {
152+
return fmt.Errorf("invalid username %q: %w", initOpts.Username, ldefine.RegexError)
153+
}
154+
146155
// Check if machine already exists
147156
_, exists, err := shim.VMExists(initOpts.Name, []vmconfigs.VMProvider{provider})
148157
if err != nil {

pkg/machine/config_test.go

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,79 +3,12 @@
33
package machine
44

55
import (
6-
"net"
7-
"net/url"
86
"path/filepath"
9-
"reflect"
107
"testing"
118

12-
"github.com/containers/podman/v5/pkg/machine/connection"
139
"github.com/stretchr/testify/assert"
1410
)
1511

16-
func TestRemoteConnectionType_MakeSSHURL(t *testing.T) {
17-
var (
18-
host = "foobar"
19-
path = "/path/to/socket"
20-
rc = "ssh"
21-
username = "core"
22-
)
23-
type args struct {
24-
host string
25-
path string
26-
port string
27-
userName string
28-
}
29-
tests := []struct {
30-
name string
31-
rc connection.RemoteConnectionType
32-
args args
33-
want url.URL
34-
}{
35-
{
36-
name: "Good no port",
37-
rc: "ssh",
38-
args: args{
39-
host: host,
40-
path: path,
41-
port: "",
42-
userName: username,
43-
},
44-
want: url.URL{
45-
Scheme: rc,
46-
User: url.User(username),
47-
Host: host,
48-
Path: path,
49-
ForceQuery: false,
50-
},
51-
},
52-
{
53-
name: "Good with port",
54-
rc: "ssh",
55-
args: args{
56-
host: host,
57-
path: path,
58-
port: "222",
59-
userName: username,
60-
},
61-
want: url.URL{
62-
Scheme: rc,
63-
User: url.User(username),
64-
Host: net.JoinHostPort(host, "222"),
65-
Path: path,
66-
ForceQuery: false,
67-
},
68-
},
69-
}
70-
for _, tt := range tests {
71-
t.Run(tt.name, func(t *testing.T) {
72-
if got := tt.rc.MakeSSHURL(tt.args.host, tt.args.path, tt.args.port, tt.args.userName); !reflect.DeepEqual(got, tt.want) { //nolint: scopelint
73-
t.Errorf("MakeSSHURL() = %v, want %v", got, tt.want) //nolint: scopelint
74-
}
75-
})
76-
}
77-
}
78-
7912
func TestGetSSHIdentityPath(t *testing.T) {
8013
name := "p-test"
8114
datadir, err := GetGlobalDataDir()

pkg/machine/connection/add.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package connection
22

33
import (
44
"fmt"
5-
"net/url"
65
"strconv"
76

87
"github.com/containers/podman/v5/pkg/machine/define"
@@ -15,22 +14,25 @@ func AddSSHConnectionsToPodmanSocket(uid, port int, identityPath, name, remoteUs
1514
fmt.Println("An ignition path was provided. No SSH connection was added to Podman")
1615
return nil
1716
}
18-
uri := SSHRemoteConnection.MakeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername)
19-
uriRoot := SSHRemoteConnection.MakeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root")
17+
uri := makeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername)
18+
uriRoot := makeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root")
2019

21-
uris := []url.URL{uri, uriRoot}
22-
names := []string{name, name + "-root"}
20+
cons := []connection{
21+
{
22+
name: name,
23+
uri: uri,
24+
},
25+
{
26+
name: name + "-root",
27+
uri: uriRoot,
28+
},
29+
}
2330

2431
// The first connection defined when connections is empty will become the default
2532
// regardless of IsDefault, so order according to rootful
2633
if opts.Rootful {
27-
uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0]
34+
cons[0], cons[1] = cons[1], cons[0]
2835
}
2936

30-
for i := 0; i < 2; i++ {
31-
if err := AddConnection(&uris[i], names[i], identityPath, opts.IsDefault && i == 0); err != nil {
32-
return err
33-
}
34-
}
35-
return nil
37+
return addConnection(cons, identityPath, opts.IsDefault)
3638
}

pkg/machine/connection/connection.go

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,40 @@ import (
1515

1616
const LocalhostIP = "127.0.0.1"
1717

18-
func AddConnection(uri fmt.Stringer, name, identity string, isDefault bool) error {
18+
type connection struct {
19+
name string
20+
uri *url.URL
21+
}
22+
23+
func addConnection(cons []connection, identity string, isDefault bool) error {
1924
if len(identity) < 1 {
2025
return errors.New("identity must be defined")
2126
}
2227

2328
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
24-
if _, ok := cfg.Connection.Connections[name]; ok {
25-
return errors.New("cannot overwrite connection")
26-
}
29+
for i, con := range cons {
30+
if _, ok := cfg.Connection.Connections[con.name]; ok {
31+
return fmt.Errorf("cannot overwrite connection %q", con.name)
32+
}
2733

28-
dst := config.Destination{
29-
URI: uri.String(),
30-
IsMachine: true,
31-
Identity: identity,
32-
}
34+
dst := config.Destination{
35+
URI: con.uri.String(),
36+
IsMachine: true,
37+
Identity: identity,
38+
}
3339

34-
if isDefault {
35-
cfg.Connection.Default = name
36-
}
40+
if isDefault && i == 0 {
41+
cfg.Connection.Default = con.name
42+
}
3743

38-
if cfg.Connection.Connections == nil {
39-
cfg.Connection.Connections = map[string]config.Destination{
40-
name: dst,
44+
if cfg.Connection.Connections == nil {
45+
cfg.Connection.Connections = map[string]config.Destination{
46+
con.name: dst,
47+
}
48+
cfg.Connection.Default = con.name
49+
} else {
50+
cfg.Connection.Connections[con.name] = dst
4151
}
42-
cfg.Connection.Default = name
43-
} else {
44-
cfg.Connection.Connections[name] = dst
4552
}
4653

4754
return nil
@@ -108,27 +115,19 @@ func RemoveFilesAndConnections(files []string, names ...string) {
108115
}
109116
}
110117

111-
type RemoteConnectionType string
112-
113-
var SSHRemoteConnection RemoteConnectionType = "ssh"
114-
115-
// MakeSSHURL
116-
func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url.URL {
117-
// TODO Should this function have input verification?
118-
userInfo := url.User(userName)
119-
uri := url.URL{
120-
Scheme: "ssh",
121-
Opaque: "",
122-
User: userInfo,
123-
Host: host,
124-
Path: path,
125-
RawPath: "",
126-
ForceQuery: false,
127-
RawQuery: "",
128-
Fragment: "",
129-
}
118+
// makeSSHURL creates a URL from the given input
119+
func makeSSHURL(host, path, port, userName string) *url.URL {
120+
var hostname string
130121
if len(port) > 0 {
131-
uri.Host = net.JoinHostPort(uri.Hostname(), port)
122+
hostname = net.JoinHostPort(host, port)
123+
} else {
124+
hostname = host
125+
}
126+
userInfo := url.User(userName)
127+
return &url.URL{
128+
Scheme: "ssh",
129+
User: userInfo,
130+
Host: hostname,
131+
Path: path,
132132
}
133-
return uri
134133
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//go:build amd64 || arm64
2+
3+
package connection
4+
5+
import (
6+
"net"
7+
"net/url"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func Test_makeSSHURL(t *testing.T) {
14+
var (
15+
host = "foobar"
16+
path = "/path/to/socket"
17+
rc = "ssh"
18+
username = "core"
19+
)
20+
type args struct {
21+
host string
22+
path string
23+
port string
24+
userName string
25+
}
26+
tests := []struct {
27+
name string
28+
args args
29+
want *url.URL
30+
}{
31+
{
32+
name: "Good no port",
33+
args: args{
34+
host: host,
35+
path: path,
36+
port: "",
37+
userName: username,
38+
},
39+
want: &url.URL{
40+
Scheme: rc,
41+
User: url.User(username),
42+
Host: host,
43+
Path: path,
44+
},
45+
},
46+
{
47+
name: "Good with port",
48+
args: args{
49+
host: host,
50+
path: path,
51+
port: "222",
52+
userName: username,
53+
},
54+
want: &url.URL{
55+
Scheme: rc,
56+
User: url.User(username),
57+
Host: net.JoinHostPort(host, "222"),
58+
Path: path,
59+
},
60+
},
61+
}
62+
for _, tt := range tests {
63+
t.Run(tt.name, func(t *testing.T) {
64+
got := makeSSHURL(tt.args.host, tt.args.path, tt.args.port, tt.args.userName)
65+
assert.Equal(t, tt.want, got, "URL matches")
66+
})
67+
}
68+
}

pkg/machine/e2e/init_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,19 @@ var _ = Describe("podman machine init", func() {
6666
Expect(badInit).To(Exit(125))
6767
Expect(badInit.errorToString()).To(ContainSubstring(want))
6868

69+
invalidName := "ab/cd"
70+
session, err = mb.setName(invalidName).setCmd(&i).run()
71+
Expect(err).ToNot(HaveOccurred())
72+
Expect(session).To(Exit(125))
73+
Expect(session.errorToString()).To(ContainSubstring(`invalid name "ab/cd": names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: invalid argument`))
74+
75+
i.username = "-/a"
76+
session, err = mb.setName("").setCmd(&i).run()
77+
Expect(err).ToNot(HaveOccurred())
78+
Expect(session).To(Exit(125))
79+
Expect(session.errorToString()).To(ContainSubstring(`invalid username "-/a": names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: invalid argument`))
6980
})
81+
7082
It("simple init", func() {
7183
i := new(initMachine)
7284
session, err := mb.setCmd(i.withImagePath(mb.imagePath)).run()

0 commit comments

Comments
 (0)