blob: 6ea2cb2648162b87a023a736f8c90061da8e4268 [file] [log] [blame]
John Wedig2098dab2021-09-14 13:56:28 -07001
2#include "estoraged.hpp"
3
John Edward Broadbent59dffa62022-01-13 17:41:32 -08004#include "cryptErase.hpp"
John Wedigb810c922021-11-17 16:38:03 -08005#include "cryptsetupInterface.hpp"
John Edward Broadbent7f2ab642021-11-11 21:00:38 -08006#include "pattern.hpp"
John Edward Broadbent605085a2021-11-05 13:45:45 -07007#include "sanitize.hpp"
John Edward Broadbente6ffe702021-10-14 14:03:11 -07008#include "verifyDriveGeometry.hpp"
John Edward Broadbent4bc8a102021-12-30 16:11:49 -08009#include "zero.hpp"
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -080010
John Wedigb810c922021-11-17 16:38:03 -080011#include <libcryptsetup.h>
12#include <openssl/rand.h>
John Wedigb810c922021-11-17 16:38:03 -080013
14#include <phosphor-logging/lg2.hpp>
John Wedig67a47442022-04-05 17:21:29 -070015#include <sdbusplus/asio/object_server.hpp>
John Wedig972c3fa2021-12-29 17:30:41 -080016#include <xyz/openbmc_project/Common/error.hpp>
John Wedigb810c922021-11-17 16:38:03 -080017
Ed Tanous82897c32022-02-21 14:11:59 -080018#include <cstdlib>
John Wedigb810c922021-11-17 16:38:03 -080019#include <filesystem>
John Wedig2098dab2021-09-14 13:56:28 -070020#include <iostream>
John Wedig67a47442022-04-05 17:21:29 -070021#include <string>
John Wedigb810c922021-11-17 16:38:03 -080022#include <string_view>
John Wedig67a47442022-04-05 17:21:29 -070023#include <utility>
John Wedig2098dab2021-09-14 13:56:28 -070024#include <vector>
25
26namespace estoraged
27{
28
John Wedig972c3fa2021-12-29 17:30:41 -080029using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
John Wedig972c3fa2021-12-29 17:30:41 -080030using sdbusplus::xyz::openbmc_project::Common::Error::UnsupportedRequest;
John Wedig67a47442022-04-05 17:21:29 -070031using sdbusplus::xyz::openbmc_project::Inventory::Item::server::Volume;
John Wedigb810c922021-11-17 16:38:03 -080032
John Wedig67a47442022-04-05 17:21:29 -070033EStoraged::EStoraged(sdbusplus::asio::object_server& server,
34 const std::string& devPath, const std::string& luksName,
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070035 uint64_t size, uint8_t lifeTime,
John Wedig67a47442022-04-05 17:21:29 -070036 std::unique_ptr<CryptsetupInterface> cryptInterface,
37 std::unique_ptr<FilesystemInterface> fsInterface) :
38 devPath(devPath),
39 containerName(luksName), mountPoint("/mnt/" + luksName + "_fs"),
40 lockedProperty(false), cryptIface(std::move(cryptInterface)),
41 fsIface(std::move(fsInterface)), objectServer(server)
42{
43 /* Get the filename of the device (without "/dev/"). */
44 std::string deviceName = std::filesystem::path(devPath).filename().string();
45 /* DBus object path */
46 std::string path = "/xyz/openbmc_project/inventory/storage/" + deviceName;
47
48 /* Add Volume interface. */
49 volumeInterface = objectServer.add_interface(
50 path, "xyz.openbmc_project.Inventory.Item.Volume");
51 volumeInterface->register_method(
52 "FormatLuks", [this](const std::vector<uint8_t>& password,
53 Volume::FilesystemType type) {
54 this->formatLuks(password, type);
55 });
56 volumeInterface->register_method(
57 "Erase",
58 [this](Volume::EraseMethod eraseType) { this->erase(eraseType); });
59 volumeInterface->register_method("Lock", [this]() { this->lock(); });
60 volumeInterface->register_method(
61 "Unlock",
62 [this](std::vector<uint8_t>& password) { this->unlock(password); });
63 volumeInterface->register_method(
64 "ChangePassword", [this](const std::vector<uint8_t>& oldPassword,
65 const std::vector<uint8_t>& newPassword) {
66 this->changePassword(oldPassword, newPassword);
67 });
68 volumeInterface->register_property_r(
69 "Locked", lockedProperty, sdbusplus::vtable::property_::emits_change,
70 [this](bool& value) {
71 value = this->isLocked();
72 return value;
73 });
74
75 /* Add Drive interface. */
76 driveInterface = objectServer.add_interface(
77 path, "xyz.openbmc_project.Inventory.Item.Drive");
78 driveInterface->register_property("Capacity", size);
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070079 driveInterface->register_property("PredictedMediaLifeLeftPercent",
80 lifeTime);
John Wedig67a47442022-04-05 17:21:29 -070081
82 volumeInterface->initialize();
83 driveInterface->initialize();
84}
85
86EStoraged::~EStoraged()
87{
88 objectServer.remove_interface(volumeInterface);
89 objectServer.remove_interface(driveInterface);
90}
91
92void EStoraged::formatLuks(const std::vector<uint8_t>& password,
93 Volume::FilesystemType type)
John Wedig2098dab2021-09-14 13:56:28 -070094{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -080095 std::string msg = "OpenBMC.0.1.DriveFormat";
96 lg2::info("Starting format", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -080097
John Wedig67a47442022-04-05 17:21:29 -070098 if (type != Volume::FilesystemType::ext4)
John Wedig972c3fa2021-12-29 17:30:41 -080099 {
100 lg2::error("Only ext4 filesystems are supported currently",
101 "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.FormatFail"));
102 throw UnsupportedRequest();
103 }
104
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700105 formatLuksDev(password);
106 activateLuksDev(password);
John Wedigb810c922021-11-17 16:38:03 -0800107
108 createFilesystem();
109 mountFilesystem();
John Wedig2098dab2021-09-14 13:56:28 -0700110}
111
John Wedig67a47442022-04-05 17:21:29 -0700112void EStoraged::erase(Volume::EraseMethod inEraseMethod)
John Wedig2098dab2021-09-14 13:56:28 -0700113{
114 std::cerr << "Erasing encrypted eMMC" << std::endl;
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700115 lg2::info("Starting erase", "REDFISH_MESSAGE_ID",
116 std::string("OpenBMC.0.1.DriveErase"));
117 switch (inEraseMethod)
118 {
John Wedig67a47442022-04-05 17:21:29 -0700119 case Volume::EraseMethod::CryptoErase:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700120 {
John Edward Broadbent59dffa62022-01-13 17:41:32 -0800121 CryptErase myCryptErase(devPath);
122 myCryptErase.doErase();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700123 break;
124 }
John Wedig67a47442022-04-05 17:21:29 -0700125 case Volume::EraseMethod::VerifyGeometry:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700126 {
127 VerifyDriveGeometry myVerifyGeometry(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700128 myVerifyGeometry.geometryOkay();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700129 break;
130 }
John Wedig67a47442022-04-05 17:21:29 -0700131 case Volume::EraseMethod::LogicalOverWrite:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700132 {
John Edward Broadbent7f2ab642021-11-11 21:00:38 -0800133 Pattern myErasePattern(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700134 myErasePattern.writePattern();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700135 break;
136 }
John Wedig67a47442022-04-05 17:21:29 -0700137 case Volume::EraseMethod::LogicalVerify:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700138 {
John Edward Broadbent7f2ab642021-11-11 21:00:38 -0800139 Pattern myErasePattern(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700140 myErasePattern.verifyPattern();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700141 break;
142 }
John Wedig67a47442022-04-05 17:21:29 -0700143 case Volume::EraseMethod::VendorSanitize:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700144 {
John Edward Broadbent605085a2021-11-05 13:45:45 -0700145 Sanitize mySanitize(devPath);
146 mySanitize.doSanitize();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700147 break;
148 }
John Wedig67a47442022-04-05 17:21:29 -0700149 case Volume::EraseMethod::ZeroOverWrite:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700150 {
John Edward Broadbent4bc8a102021-12-30 16:11:49 -0800151 Zero myZero(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700152 myZero.writeZero();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700153 break;
154 }
John Wedig67a47442022-04-05 17:21:29 -0700155 case Volume::EraseMethod::ZeroVerify:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700156 {
John Edward Broadbent4bc8a102021-12-30 16:11:49 -0800157 Zero myZero(devPath);
John Edward Broadbenta6e3b992022-03-17 14:33:15 -0700158 myZero.verifyZero();
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700159 break;
160 }
John Wedig67a47442022-04-05 17:21:29 -0700161 case Volume::EraseMethod::SecuredLocked:
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700162 {
John Edward Broadbentf59b7292022-02-15 15:07:15 -0800163 if (isLocked())
164 {
165 lock();
166 }
167 // TODO: implement hardware locking
168 // Until that is done, we can lock using eStoraged::lock()
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700169 break;
170 }
171 }
John Wedig2098dab2021-09-14 13:56:28 -0700172}
173
Ed Tanous82897c32022-02-21 14:11:59 -0800174void EStoraged::lock()
John Wedig2098dab2021-09-14 13:56:28 -0700175{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800176 std::string msg = "OpenBMC.0.1.DriveLock";
177 lg2::info("Starting lock", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800178
179 unmountFilesystem();
180 deactivateLuksDev();
John Wedig2098dab2021-09-14 13:56:28 -0700181}
182
Ed Tanous82897c32022-02-21 14:11:59 -0800183void EStoraged::unlock(std::vector<uint8_t> password)
John Wedig2098dab2021-09-14 13:56:28 -0700184{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800185 std::string msg = "OpenBMC.0.1.DriveUnlock";
186 lg2::info("Starting unlock", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800187
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700188 activateLuksDev(std::move(password));
John Wedigb810c922021-11-17 16:38:03 -0800189 mountFilesystem();
John Wedig2098dab2021-09-14 13:56:28 -0700190}
191
John Wedig67a47442022-04-05 17:21:29 -0700192void EStoraged::changePassword(const std::vector<uint8_t>& /*oldPassword*/,
193 const std::vector<uint8_t>& /*newPassword*/)
John Wedig2098dab2021-09-14 13:56:28 -0700194{
195 std::cerr << "Changing password for encrypted eMMC" << std::endl;
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700196 lg2::info("Starting change password", "REDFISH_MESSAGE_ID",
197 std::string("OpenBMC.0.1.DrivePasswordChanged"));
John Wedig2098dab2021-09-14 13:56:28 -0700198}
199
Ed Tanous82897c32022-02-21 14:11:59 -0800200bool EStoraged::isLocked() const
John Wedigb810c922021-11-17 16:38:03 -0800201{
John Wedig67a47442022-04-05 17:21:29 -0700202 return lockedProperty;
John Wedigb810c922021-11-17 16:38:03 -0800203}
204
Ed Tanous82897c32022-02-21 14:11:59 -0800205std::string_view EStoraged::getMountPoint() const
John Wedigb810c922021-11-17 16:38:03 -0800206{
207 return mountPoint;
208}
209
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700210void EStoraged::formatLuksDev(std::vector<uint8_t> password)
John Wedigb810c922021-11-17 16:38:03 -0800211{
212 lg2::info("Formatting device {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
213 std::string("OpenBMC.0.1.FormatLuksDev"));
214
215 /* Generate the volume key. */
216 const std::size_t keySize = 64;
217 std::vector<uint8_t> volumeKey(keySize);
218 if (RAND_bytes(volumeKey.data(), keySize) != 1)
219 {
220 lg2::error("Failed to create volume key", "REDFISH_MESSAGE_ID",
221 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800222 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800223 }
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700224
225 /* Create the handle. */
226 CryptHandle cryptHandle(devPath);
227
John Wedigb810c922021-11-17 16:38:03 -0800228 /* Format the LUKS encrypted device. */
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700229 int retval = cryptIface->cryptFormat(
230 cryptHandle.get(), CRYPT_LUKS2, "aes", "xts-plain64", nullptr,
231 reinterpret_cast<const char*>(volumeKey.data()), volumeKey.size(),
232 nullptr);
John Wedigb810c922021-11-17 16:38:03 -0800233 if (retval < 0)
234 {
235 lg2::error("Failed to format encrypted device: {RETVAL}", "RETVAL",
236 retval, "REDFISH_MESSAGE_ID",
237 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800238 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800239 }
240
241 /* Device is now encrypted. */
242 locked(true);
243
244 /* Set the password. */
245 retval = cryptIface->cryptKeyslotAddByVolumeKey(
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700246 cryptHandle.get(), CRYPT_ANY_SLOT, nullptr, 0,
John Wedigb810c922021-11-17 16:38:03 -0800247 reinterpret_cast<const char*>(password.data()), password.size());
248
249 if (retval < 0)
250 {
251 lg2::error("Failed to set encryption password", "REDFISH_MESSAGE_ID",
252 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800253 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800254 }
255
256 lg2::info("Encrypted device {DEV} successfully formatted", "DEV", devPath,
257 "REDFISH_MESSAGE_ID",
258 std::string("OpenBMC.0.1.FormatLuksDevSuccess"));
259}
260
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700261void EStoraged::activateLuksDev(std::vector<uint8_t> password)
John Wedigb810c922021-11-17 16:38:03 -0800262{
263 lg2::info("Activating LUKS dev {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
264 std::string("OpenBMC.0.1.ActivateLuksDev"));
265
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700266 /* Create the handle. */
267 CryptHandle cryptHandle(devPath);
268
269 int retval = cryptIface->cryptLoad(cryptHandle.get(), CRYPT_LUKS2, nullptr);
John Wedigb810c922021-11-17 16:38:03 -0800270 if (retval < 0)
271 {
272 lg2::error("Failed to load LUKS header: {RETVAL}", "RETVAL", retval,
273 "REDFISH_MESSAGE_ID",
274 std::string("OpenBMC.0.1.ActivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800275 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800276 }
277
278 retval = cryptIface->cryptActivateByPassphrase(
John Edward Broadbentb2c86be2022-04-15 11:45:53 -0700279 cryptHandle.get(), containerName.c_str(), CRYPT_ANY_SLOT,
John Wedigb810c922021-11-17 16:38:03 -0800280 reinterpret_cast<const char*>(password.data()), password.size(), 0);
281
282 if (retval < 0)
283 {
284 lg2::error("Failed to activate LUKS dev: {RETVAL}", "RETVAL", retval,
285 "REDFISH_MESSAGE_ID",
286 std::string("OpenBMC.0.1.ActivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800287 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800288 }
289
290 /* Device is now unlocked. */
291 locked(false);
292
293 lg2::info("Successfully activated LUKS dev {DEV}", "DEV", devPath,
294 "REDFISH_MESSAGE_ID",
295 std::string("OpenBMC.0.1.ActivateLuksDevSuccess"));
296}
297
Ed Tanous82897c32022-02-21 14:11:59 -0800298void EStoraged::createFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800299{
300 /* Run the command to create the filesystem. */
301 int retval = fsIface->runMkfs(containerName);
Ed Tanous82897c32022-02-21 14:11:59 -0800302 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800303 {
304 lg2::error("Failed to create filesystem: {RETVAL}", "RETVAL", retval,
305 "REDFISH_MESSAGE_ID",
306 std::string("OpenBMC.0.1.CreateFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800307 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800308 }
309 lg2::info("Successfully created filesystem for /dev/mapper/{CONTAINER}",
310 "CONTAINER", containerName, "REDFISH_MESSAGE_ID",
311 std::string("OpenBMC.0.1.CreateFilesystemSuccess"));
312}
313
Ed Tanous82897c32022-02-21 14:11:59 -0800314void EStoraged::mountFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800315{
John Wedigb17f8252022-01-12 14:24:26 -0800316 /*
317 * Create directory for the filesystem, if it's not already present. It
318 * might already exist if, for example, the BMC reboots after creating the
319 * directory.
320 */
321 if (!fsIface->directoryExists(std::filesystem::path(mountPoint)))
John Wedigb810c922021-11-17 16:38:03 -0800322 {
John Wedigb17f8252022-01-12 14:24:26 -0800323 bool success =
324 fsIface->createDirectory(std::filesystem::path(mountPoint));
325 if (!success)
326 {
327 lg2::error("Failed to create mount point: {DIR}", "DIR", mountPoint,
328 "REDFISH_MESSAGE_ID",
329 std::string("OpenBMC.0.1.MountFilesystemFail"));
330 throw InternalFailure();
331 }
John Wedigb810c922021-11-17 16:38:03 -0800332 }
333
334 /* Run the command to mount the filesystem. */
335 std::string luksContainer("/dev/mapper/" + containerName);
336 int retval = fsIface->doMount(luksContainer.c_str(), mountPoint.c_str(),
337 "ext4", 0, nullptr);
Ed Tanous82897c32022-02-21 14:11:59 -0800338 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800339 {
340 lg2::error("Failed to mount filesystem: {RETVAL}", "RETVAL", retval,
341 "REDFISH_MESSAGE_ID",
342 std::string("OpenBMC.0.1.MountFilesystemFail"));
343 bool removeSuccess =
344 fsIface->removeDirectory(std::filesystem::path(mountPoint));
345 if (!removeSuccess)
346 {
347 lg2::error("Failed to remove mount point: {DIR}", "DIR", mountPoint,
348 "REDFISH_MESSAGE_ID",
349 std::string("OpenBMC.0.1.MountFilesystemFail"));
350 }
John Wedig972c3fa2021-12-29 17:30:41 -0800351 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800352 }
353
354 lg2::info("Successfully mounted filesystem at {DIR}", "DIR", mountPoint,
355 "REDFISH_MESSAGE_ID",
356 std::string("OpenBMC.0.1.MountFilesystemSuccess"));
357}
358
Ed Tanous82897c32022-02-21 14:11:59 -0800359void EStoraged::unmountFilesystem()
John Wedigb810c922021-11-17 16:38:03 -0800360{
361 int retval = fsIface->doUnmount(mountPoint.c_str());
Ed Tanous82897c32022-02-21 14:11:59 -0800362 if (retval != 0)
John Wedigb810c922021-11-17 16:38:03 -0800363 {
364 lg2::error("Failed to unmount filesystem: {RETVAL}", "RETVAL", retval,
365 "REDFISH_MESSAGE_ID",
366 std::string("OpenBMC.0.1.UnmountFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800367 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800368 }
369
370 /* Remove the mount point. */
371 bool success = fsIface->removeDirectory(std::filesystem::path(mountPoint));
372 if (!success)
373 {
374 lg2::error("Failed to remove mount point {DIR}", "DIR", mountPoint,
375 "REDFISH_MESSAGE_ID",
376 std::string("OpenBMC.0.1.UnmountFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800377 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800378 }
379
380 lg2::info("Successfully unmounted filesystem at {DIR}", "DIR", mountPoint,
381 "REDFISH_MESSAGE_ID",
382 std::string("OpenBMC.0.1.MountFilesystemSuccess"));
383}
384
Ed Tanous82897c32022-02-21 14:11:59 -0800385void EStoraged::deactivateLuksDev()
John Wedigb810c922021-11-17 16:38:03 -0800386{
387 lg2::info("Deactivating LUKS device {DEV}", "DEV", devPath,
388 "REDFISH_MESSAGE_ID",
389 std::string("OpenBMC.0.1.DeactivateLuksDev"));
390
391 int retval = cryptIface->cryptDeactivate(nullptr, containerName.c_str());
392 if (retval < 0)
393 {
394 lg2::error("Failed to deactivate crypt device: {RETVAL}", "RETVAL",
395 retval, "REDFISH_MESSAGE_ID",
396 std::string("OpenBMC.0.1.DeactivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800397 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800398 }
399
400 /* Device is now locked. */
401 locked(true);
402
403 lg2::info("Successfully deactivated LUKS device {DEV}", "DEV", devPath,
404 "REDFISH_MESSAGE_ID",
405 std::string("OpenBMC.0.1.DeactivateLuksDevSuccess"));
406}
407
John Wedig67a47442022-04-05 17:21:29 -0700408void EStoraged::locked(bool isLocked)
409{
410 lockedProperty = isLocked;
411}
412
John Wedig2098dab2021-09-14 13:56:28 -0700413} // namespace estoraged