-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathauth_requestor_systemd.go
More file actions
112 lines (99 loc) · 3.73 KB
/
auth_requestor_systemd.go
File metadata and controls
112 lines (99 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2021 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package secboot
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
)
// SystemdAuthRequestorStringFn is a callback used to supply translated messages
// to the systemd implementation of AuthRequestor.RequestUserCredential. The name
// is a string supplied via the [WithAuthRequestorUserVisibleName] option, and the
// path is the storage container path.
type SystemdAuthRequestorStringFn func(name, path string, authTypes UserAuthType) (string, error)
type systemdAuthRequestor struct {
console io.Writer
stringFn SystemdAuthRequestorStringFn
lastRequestUserCredentialPath string
}
func (r *systemdAuthRequestor) RequestUserCredential(ctx context.Context, name, path string, authTypes UserAuthType) (string, UserAuthType, error) {
msg, err := r.stringFn(name, path, authTypes)
if err != nil {
return "", 0, fmt.Errorf("cannot request message string: %w", err)
}
cmd := exec.CommandContext(
ctx, "systemd-ask-password",
"--icon", "drive-harddisk",
"--id", filepath.Base(os.Args[0])+":"+path,
msg)
out := new(bytes.Buffer)
cmd.Stdout = out
cmd.Stdin = os.Stdin
if err := cmd.Run(); err != nil {
return "", 0, fmt.Errorf("cannot execute systemd-ask-password: %w", err)
}
result, err := out.ReadString('\n')
if err != nil {
// The only error returned from bytes.Buffer.ReadString is io.EOF.
return "", 0, errors.New("systemd-ask-password output is missing terminating newline")
}
r.lastRequestUserCredentialPath = path
return strings.TrimRight(result, "\n"), authTypes, nil
}
func (r *systemdAuthRequestor) NotifyUserAuthResult(ctx context.Context, result UserAuthResult, authTypes, exhaustedAuthTypes UserAuthType) error {
switch result {
case UserAuthResultFailed:
fmt.Fprintf(r.console, "Incorrect %s for %s\n", formatUserAuthTypeString(authTypes), r.lastRequestUserCredentialPath)
if exhaustedAuthTypes != UserAuthType(0) {
fmt.Fprintf(r.console, "No more %s tries remaining\n", formatUserAuthTypeString(exhaustedAuthTypes))
}
case UserAuthResultInvalidFormat:
fmt.Fprintf(r.console, "Incorrectly formatted %s\n", formatUserAuthTypeString(authTypes))
}
r.lastRequestUserCredentialPath = ""
return nil
}
// NewSystemdAuthRequestor creates an implementation of AuthRequestor that
// delegates to the systemd-ask-password binary. The caller supplies a callback
// to supply messages for user auth requests. The console argument is used by
// the implementation of [AuthRequestor.NotifyUserAuthResult] where result is
// not [UserAuthResultSuccess]. If not provided, it defaults to [os.Stderr].
//
// This will return [ErrAuthRequestorNotAvailable] if systemd-ask-password is
// not available.
func NewSystemdAuthRequestor(console io.Writer, stringFn SystemdAuthRequestorStringFn) (AuthRequestor, error) {
if _, err := exec.LookPath("systemd-ask-password"); err != nil {
return nil, ErrAuthRequestorNotAvailable
}
if console == nil {
console = os.Stderr
}
if stringFn == nil {
return nil, errors.New("must supply a SystemdAuthRequestorStringFn")
}
return &systemdAuthRequestor{
console: console,
stringFn: stringFn,
}, nil
}