-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathauth_requestor_systemd.go
122 lines (104 loc) · 3.68 KB
/
auth_requestor_systemd.go
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
113
114
115
116
117
118
119
120
121
122
// -*- 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"
"errors"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
"golang.org/x/xerrors"
)
type askPasswordMsgParams struct {
VolumeName string
SourceDevicePath string
// PartLabel string
// LUKS2Label string
}
type systemdAuthRequestor struct {
passphraseTmpl *template.Template
recoveryKeyTmpl *template.Template
}
func (r *systemdAuthRequestor) askPassword(sourceDevicePath, msg string) (string, error) {
cmd := exec.Command(
"systemd-ask-password",
"--icon", "drive-harddisk",
"--id", filepath.Base(os.Args[0])+":"+sourceDevicePath,
msg)
out := new(bytes.Buffer)
cmd.Stdout = out
cmd.Stdin = os.Stdin
if err := cmd.Run(); err != nil {
return "", xerrors.Errorf("cannot execute systemd-ask-password: %v", err)
}
result, err := out.ReadString('\n')
if err != nil {
// The only error returned from bytes.Buffer.ReadString is io.EOF.
return "", errors.New("systemd-ask-password output is missing terminating newline")
}
return strings.TrimRight(result, "\n"), nil
}
func (r *systemdAuthRequestor) RequestPassphrase(volumeName, sourceDevicePath string) (string, error) {
params := askPasswordMsgParams{
VolumeName: volumeName,
SourceDevicePath: sourceDevicePath}
msg := new(bytes.Buffer)
if err := r.passphraseTmpl.Execute(msg, params); err != nil {
return "", xerrors.Errorf("cannot execute message template: %w", err)
}
return r.askPassword(sourceDevicePath, msg.String())
}
func (r *systemdAuthRequestor) RequestRecoveryKey(volumeName, sourceDevicePath string) (RecoveryKey, error) {
params := askPasswordMsgParams{
VolumeName: volumeName,
SourceDevicePath: sourceDevicePath}
msg := new(bytes.Buffer)
if err := r.recoveryKeyTmpl.Execute(msg, params); err != nil {
return RecoveryKey{}, xerrors.Errorf("cannot execute message template: %w", err)
}
passphrase, err := r.askPassword(sourceDevicePath, msg.String())
if err != nil {
return RecoveryKey{}, err
}
key, err := ParseRecoveryKey(passphrase)
if err != nil {
return RecoveryKey{}, xerrors.Errorf("cannot parse recovery key: %w", err)
}
return key, nil
}
// NewSystemdAuthRequestor creates an implementation of AuthRequestor that
// delegates to the systemd-ask-password binary. The supplied templates are
// used to compose the messages that will be displayed when requesting a
// credential. The template will be executed with the following parameters:
// - .VolumeName: The name that the LUKS container will be mapped to.
// - .SourceDevicePath: The device path of the LUKS container.
func NewSystemdAuthRequestor(passphraseTmpl, recoveryKeyTmpl string) (AuthRequestor, error) {
pt, err := template.New("passphraseMsg").Parse(passphraseTmpl)
if err != nil {
return nil, xerrors.Errorf("cannot parse passphrase message template: %w", err)
}
rkt, err := template.New("recoveryKeyMsg").Parse(recoveryKeyTmpl)
if err != nil {
return nil, xerrors.Errorf("cannot parse recovery key message template: %w", err)
}
return &systemdAuthRequestor{
passphraseTmpl: pt,
recoveryKeyTmpl: rkt}, nil
}