Class: Bootloader::Bls

Inherits:
Object
  • Object
show all
Extended by:
Yast::I18n
Includes:
Yast::Logger
Defined in:
src/lib/bootloader/bls.rb

Overview

Represents bls compatile system calls which can be used e.g. by grub2-bls and systemd-boot

Constant Summary collapse

SDBOOTUTIL =
"/usr/bin/sdbootutil"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBls



21
22
23
# File 'src/lib/bootloader/bls.rb', line 21

def initialize
  textdomain "bootloader"
end

Class Method Details

.ask_for_fido2_key(device_name) ⇒ Object



203
204
205
206
207
208
209
210
211
212
# File 'src/lib/bootloader/bls.rb', line 203

def self.ask_for_fido2_key(device_name)
  Yast::Popup.Message(
    format(_(
      "Please ensure that a FIDO2 Key is connected to your system in order to " \
      "enroll the authentication for device %{device}.\n" \
      "You will be asked to push the FIDO2 key button twice for " \
      "transfering the information."
    ), device: device_name)
  )
end

.create_menu_entriesObject



25
26
27
28
29
30
31
32
33
34
35
# File 'src/lib/bootloader/bls.rb', line 25

def self.create_menu_entries
  Yast::Execute.on_target!(SDBOOTUTIL, "add-all-kernels")
rescue Cheetah::ExecutionFailed => e
  Yast::Report.Error(
    format(_(
             "Cannot create boot menu entry:\n" \
             "Command `%{command}`.\n" \
             "Error output: %{stderr}"
           ), command: e.commands.inspect, stderr: e.stderr)
  )
end

.default_menuObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'src/lib/bootloader/bls.rb', line 108

def self.default_menu
  begin
    output = Yast::Execute.on_target!(SDBOOTUTIL, "get-default", stdout: :capture)
  rescue Cheetah::ExecutionFailed => e
    error_message = format(_(
                             "Cannot read default menu:\n" \
                             "Command `%{command}`.\n" \
                             "Error output: %{stderr}"
                           ), command: e.commands.inspect, stderr: e.stderr)
    if Yast::Stage.initial && Yast::Mode.update
      Yast::Report.Warning(error_message)
    else
      Yast::Report.Error(error_message)
    end
    output = ""
  end
  output.strip
end

.export_password(pwd, kind) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'src/lib/bootloader/bls.rb', line 182

def self.export_password(pwd, kind)
  if pwd.empty?
    Yast::Report.Error(_("Cannot pass empty password via the keyring."))
    return
  end

  begin
    Yast::Execute.on_target!("keyctl", "padd", "user", kind, "@u",
      recorder: Yast::ReducedRecorder.new(skip: :stdin),
      stdin:    pwd)
  rescue Cheetah::ExecutionFailed => e
    Yast::Report.Error(
      format(_(
               "Cannot pass the password via the keyring:\n" \
               "Command `%{command}`.\n" \
               "Error output: %{stderr}"
             ), command: e.commands.inspect, stderr: e.stderr)
    )
  end
end

.generate_machine_idObject

rubocop:enable Metrics/AbcSize



167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'src/lib/bootloader/bls.rb', line 167

def self.generate_machine_id
  Yast::SCR.Execute(Yast::Path.new(".target.remove"), "/etc/machine-id")
  begin
    Yast::Execute.on_target!("/bin/systemd-machine-id-setup")
  rescue Cheetah::ExecutionFailed => e
    Yast::Report.Error(
      format(_(
               "Cannot create machine-id:\n" \
               "Command `%{command}`.\n" \
               "Error output: %{stderr}"
             ), command: e.commands.inspect, stderr: e.stderr)
    )
  end
end

.install_bootloaderObject



37
38
39
40
41
42
43
44
45
46
47
# File 'src/lib/bootloader/bls.rb', line 37

def self.install_bootloader
  Yast::Execute.on_target!(SDBOOTUTIL, "install")
rescue Cheetah::ExecutionFailed => e
  Yast::Report.Error(
  format(_(
           "Cannot install bootloader:\n" \
           "Command `%{command}`.\n" \
           "Error output: %{stderr}"
         ), command: e.commands.inspect, stderr: e.stderr)
)
end


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'src/lib/bootloader/bls.rb', line 73

def self.menu_timeout
  begin
    output = Yast::Execute.on_target!(SDBOOTUTIL, "get-timeout", stdout: :capture).to_i
  rescue Cheetah::ExecutionFailed => e
    error_message = format(_(
                             "Cannot read boot menu timeout:\n" \
                             "Command `%{command}`.\n" \
                             "Error output: %{stderr}"
                           ), command: e.commands.inspect, stderr: e.stderr)
    if Yast::Stage.initial && Yast::Mode.update
      Yast::Report.Warning(error_message)
    else
      Yast::Report.Error(error_message)
    end
    output = -2 # -1 will be returned from sdbootutil for menu-force
  end
  output
end

.set_authenticationObject

Enable TPM2/FIDO2 if it is required rubocop:disable Metrics/AbcSize



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'src/lib/bootloader/bls.rb', line 129

def self.set_authentication
  generate_machine_id
  devicegraph = Y2Storage::StorageManager.instance.staging

  devicegraph.encryptions&.each do |d|
    next unless d.method.id == :systemd_fde

    # No enrollment is needed. Setting password while
    # encryption is enough.
    next if d.authentication.value == "password"

    # Password used by systemd-cryptenroll to unlock the device (LUKS2)
    export_password(d.password, "cryptenroll")
    # Password used by sdbootutil as a recovery PIN
    if d.authentication.value == "tpm2" || d.authentication.value == "tpm2+pin"
      export_password(d.password, "sdbootutil")
    end
    # Password used by sdbootutil as a TPM2 PIN
    export_password(d.password, "sdbootutil-pin") if d.authentication.value == "tpm2+pin"

    ask_for_fido2_key(d.blk_device.name) if d.authentication.value == "fido2"
    begin
      Yast::Execute.on_target!(SDBOOTUTIL,
        "enroll", "--method=#{d.authentication.value}",
        "--devices=#{d.blk_device.name}")
    rescue Cheetah::ExecutionFailed => e
      Yast::Report.Error(
        format(_(
                 "Cannot enroll authentication:\n" \
                 "Command `%{command}`.\n" \
                 "Error output: %{stderr}"
               ), command: e.commands.inspect, stderr: e.stderr)
      )
    end
  end
end

.update_bootloaderObject



49
50
51
52
53
54
55
56
57
58
59
# File 'src/lib/bootloader/bls.rb', line 49

def self.update_bootloader
  Yast::Execute.on_target!(SDBOOTUTIL, "update-all-entries")
rescue Cheetah::ExecutionFailed => e
  Yast::Report.Error(
  format(_(
           "Cannot update bootloader:\n" \
           "Command `%{command}`.\n" \
           "Error output: %{stderr}"
         ), command: e.commands.inspect, stderr: e.stderr)
)
end

.write_default_menu(default) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'src/lib/bootloader/bls.rb', line 92

def self.write_default_menu(default)
  return if default.empty?

  begin
    Yast::Execute.on_target!(SDBOOTUTIL, "set-default", default)
  rescue Cheetah::ExecutionFailed => e
    Yast::Report.Error(
      format(_(
               "Cannot write default boot menu entry:\n" \
               "Command `%{command}`.\n" \
               "Error output: %{stderr}"
             ), command: e.commands.inspect, stderr: e.stderr)
    )
  end
end

.write_menu_timeout(timeout) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
# File 'src/lib/bootloader/bls.rb', line 61

def self.write_menu_timeout(timeout)
  Yast::Execute.on_target!(SDBOOTUTIL, "set-timeout", "--", timeout)
rescue Cheetah::ExecutionFailed => e
  Yast::Report.Error(
  format(_(
           "Cannot write boot menu timeout:\n" \
           "Command `%{command}`.\n" \
           "Error output: %{stderr}"
         ), command: e.commands.inspect, stderr: e.stderr)
)
end