Skip to content

Commit e3d9801

Browse files
authored
add kdialog for kubuntu key escrow (#24405)
1 parent 2b071a9 commit e3d9801

File tree

13 files changed

+416
-52
lines changed

13 files changed

+416
-52
lines changed

orbit/changes/23697-kubuntu-luks

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* added support for kdialog linux key escrow prompts for compatibility with kubuntu systems

orbit/cmd/orbit/orbit.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import (
3939
"github.com/fleetdm/fleet/v4/orbit/pkg/update"
4040
"github.com/fleetdm/fleet/v4/orbit/pkg/update/filestore"
4141
"github.com/fleetdm/fleet/v4/orbit/pkg/user"
42-
"github.com/fleetdm/fleet/v4/orbit/pkg/zenity"
4342
"github.com/fleetdm/fleet/v4/pkg/certificate"
4443
"github.com/fleetdm/fleet/v4/pkg/file"
4544
retrypkg "github.com/fleetdm/fleet/v4/pkg/retry"
@@ -938,7 +937,7 @@ func main() {
938937
orbitClient.RegisterConfigReceiver(update.ApplyWindowsMDMEnrollmentFetcherMiddleware(windowsMDMEnrollmentCommandFrequency, orbitHostInfo.HardwareUUID, orbitClient))
939938
orbitClient.RegisterConfigReceiver(update.ApplyWindowsMDMBitlockerFetcherMiddleware(windowsMDMBitlockerCommandFrequency, orbitClient))
940939
case "linux":
941-
orbitClient.RegisterConfigReceiver(luks.New(orbitClient, zenity.New()))
940+
orbitClient.RegisterConfigReceiver(luks.New(orbitClient))
942941
}
943942

944943
flagUpdateReceiver := update.NewFlagReceiver(orbitClient.TriggerOrbitRestart, update.FlagUpdateOptions{

orbit/pkg/dialog/dialog.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dialog
22

33
import (
4-
"context"
54
"errors"
65
"time"
76
)
@@ -20,10 +19,10 @@ var (
2019
type Dialog interface {
2120
// ShowEntry displays a dialog that accepts end user input. It returns the entered
2221
// text or errors ErrCanceled, ErrTimeout, or ErrUnknown.
23-
ShowEntry(ctx context.Context, opts EntryOptions) ([]byte, error)
22+
ShowEntry(opts EntryOptions) ([]byte, error)
2423
// ShowInfo displays a dialog that displays information. It returns an error if the dialog
2524
// could not be displayed.
26-
ShowInfo(ctx context.Context, opts InfoOptions) error
25+
ShowInfo(opts InfoOptions) error
2726
// Progress displays a dialog that shows progress. It waits until the
2827
// context is cancelled.
2928
ShowProgress(opts ProgressOptions) (cancelFunc func() error, err error)

orbit/pkg/execuser/execuser.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22
// SYSTEM service on Windows) as the current login user.
33
package execuser
44

5-
import "io"
5+
import (
6+
"io"
7+
"time"
8+
)
69

710
type eopts struct {
811
env [][2]string
912
args [][2]string
1013
stderrPath string //nolint:structcheck,unused
14+
timeout time.Duration
1115
}
1216

1317
// Option allows configuring the application.
@@ -27,6 +31,13 @@ func WithArg(name, value string) Option {
2731
}
2832
}
2933

34+
// WithTimeout sets the timeout for the application. Currently only supported on Linux.
35+
func WithTimeout(duration time.Duration) Option {
36+
return func(a *eopts) {
37+
a.timeout = duration
38+
}
39+
}
40+
3041
// Run runs an application as the current login user.
3142
// It assumes the caller is running with high privileges (root on Unix, SYSTEM on Windows).
3243
//

orbit/pkg/execuser/execuser_linux.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,16 @@ func runWithOutput(path string, opts eopts) (output []byte, exitCode int, err er
6464
}
6565
}
6666

67-
cmd := exec.Command("sudo", args...)
67+
// Prefix with "timeout" and "sudo" if applicable
68+
var cmdArgs []string
69+
if opts.timeout > 0 {
70+
cmdArgs = append(cmdArgs, "timeout", fmt.Sprintf("%ds", int(opts.timeout.Seconds())))
71+
}
72+
cmdArgs = append(cmdArgs, "sudo")
73+
cmdArgs = append(cmdArgs, args...)
74+
75+
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) // #nosec G204
76+
6877
log.Printf("cmd=%s", cmd.String())
6978

7079
output, err = cmd.Output()

orbit/pkg/kdialog/kdialog.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package kdialog
2+
3+
import (
4+
"errors"
5+
"strings"
6+
"time"
7+
8+
"github.com/fleetdm/fleet/v4/orbit/pkg/dialog"
9+
"github.com/fleetdm/fleet/v4/orbit/pkg/execuser"
10+
"github.com/fleetdm/fleet/v4/orbit/pkg/platform"
11+
)
12+
13+
const kdialogProcessName = "kdialog"
14+
15+
type KDialog struct {
16+
cmdWithOutput func(timeout time.Duration, args ...string) ([]byte, int, error)
17+
cmdWithCancel func(args ...string) (cancelFunc func() error, err error)
18+
}
19+
20+
func New() *KDialog {
21+
return &KDialog{
22+
cmdWithOutput: execCmdWithOutput,
23+
cmdWithCancel: execCmdWithCancel,
24+
}
25+
}
26+
27+
func (k *KDialog) ShowEntry(opts dialog.EntryOptions) ([]byte, error) {
28+
args := []string{"--password"}
29+
if opts.Text != "" {
30+
args = append(args, opts.Text)
31+
}
32+
if opts.Title != "" {
33+
args = append(args, "--title", opts.Title)
34+
}
35+
36+
output, statusCode, err := k.cmdWithOutput(opts.TimeOut, args...)
37+
if err != nil {
38+
switch statusCode {
39+
case 1:
40+
return nil, dialog.ErrCanceled
41+
case 124:
42+
return nil, dialog.ErrTimeout
43+
default:
44+
return nil, errors.Join(dialog.ErrUnknown, err)
45+
}
46+
}
47+
48+
output = []byte(strings.TrimSuffix(string(output), "\n"))
49+
50+
return output, nil
51+
}
52+
53+
func (k *KDialog) ShowProgress(opts dialog.ProgressOptions) (func() error, error) {
54+
args := []string{"--msgbox"}
55+
if opts.Text != "" {
56+
args = append(args, opts.Text)
57+
}
58+
if opts.Title != "" {
59+
args = append(args, "--title", opts.Title)
60+
}
61+
62+
cancel, err := k.cmdWithCancel(args...)
63+
if err != nil {
64+
return nil, err
65+
}
66+
67+
return cancel, nil
68+
}
69+
70+
func (k *KDialog) ShowInfo(opts dialog.InfoOptions) error {
71+
args := []string{"--msgbox"}
72+
if opts.Text != "" {
73+
args = append(args, opts.Text)
74+
}
75+
if opts.Title != "" {
76+
args = append(args, "--title", opts.Title)
77+
}
78+
79+
_, statusCode, err := k.cmdWithOutput(opts.TimeOut, args...)
80+
if err != nil {
81+
switch statusCode {
82+
case 124:
83+
return dialog.ErrTimeout
84+
default:
85+
return errors.Join(dialog.ErrUnknown, err)
86+
}
87+
}
88+
89+
return nil
90+
}
91+
92+
func execCmdWithOutput(timeout time.Duration, args ...string) ([]byte, int, error) {
93+
var opts []execuser.Option
94+
for _, arg := range args {
95+
opts = append(opts, execuser.WithArg(arg, "")) // using empty value for positional args
96+
}
97+
98+
if timeout > 0 {
99+
opts = append(opts, execuser.WithTimeout(timeout))
100+
}
101+
102+
output, exitCode, err := execuser.RunWithOutput(kdialogProcessName, opts...)
103+
if err != nil {
104+
return nil, exitCode, err
105+
}
106+
107+
return output, exitCode, nil
108+
}
109+
110+
func execCmdWithCancel(args ...string) (func() error, error) {
111+
var opts []execuser.Option
112+
for _, arg := range args {
113+
opts = append(opts, execuser.WithArg(arg, "")) // using empty value for positional args
114+
}
115+
116+
_, err := execuser.Run(kdialogProcessName, opts...)
117+
if err != nil {
118+
return nil, err
119+
}
120+
121+
killFunc := func() error {
122+
if _, err := platform.KillAllProcessByName(kdialogProcessName); err != nil {
123+
return err
124+
}
125+
return nil
126+
}
127+
128+
return killFunc, nil
129+
}

0 commit comments

Comments
 (0)