diff options
-rw-r--r-- | hscript/disk.cc | 31 | ||||
-rw-r--r-- | hscript/disk.hh | 15 | ||||
-rw-r--r-- | hscript/script.cc | 33 | ||||
-rw-r--r-- | tests/fixtures/0189-encrypt-basic.installfile | 9 | ||||
-rw-r--r-- | tests/fixtures/0190-encrypt-duplicate.installfile | 10 | ||||
-rw-r--r-- | tests/fixtures/0191-encrypt-invalid.installfile | 9 | ||||
-rw-r--r-- | tests/fixtures/0192-encrypt-pw.installfile | 9 | ||||
-rw-r--r-- | tests/spec/validator_spec.rb | 24 |
8 files changed, 139 insertions, 1 deletions
diff --git a/hscript/disk.cc b/hscript/disk.cc index 05fb6d2..ad253b3 100644 --- a/hscript/disk.cc +++ b/hscript/disk.cc @@ -233,6 +233,37 @@ bool DiskLabel::execute(ScriptOptions options) const { } +Key *Encrypt::parseFromData(const std::string &data, int lineno, int *errors, + int *) { + std::string::size_type sep = data.find(' '); + std::string dev, pass; + + if(sep == std::string::npos) { + dev = data; + } else { + dev = data.substr(0, sep); + pass = data.substr(sep + 1); + } + + if(dev.size() < 6 || dev.compare(0, 5, "/dev/")) { + if(errors) *errors += 1; + output_error("installfile:" + std::to_string(lineno), + "encrypt: expected path to block device"); + return nullptr; + } + + return new Encrypt(lineno, dev, pass); +} + +bool Encrypt::validate(ScriptOptions) const { + return true; +} + +bool Encrypt::execute(ScriptOptions) const { + return false; +} + + /*! Parse a size string into a size and type. * @param in_size (in) The string to parse. * @param out_size (out) Where to which to write the size in bytes or %. diff --git a/hscript/disk.hh b/hscript/disk.hh index f3a8a4c..7722780 100644 --- a/hscript/disk.hh +++ b/hscript/disk.hh @@ -114,6 +114,21 @@ public: }; class Encrypt : public Key { +private: + const std::string _block; + const std::string _pw; + + Encrypt(int _line, const std::string &_b, const std::string &_p) : + Key(_line), _block(_b), _pw(_p) {} +public: + /*! Retrieve the block device that this key encrypts. */ + const std::string device() const { return this->_block; } + /*! Retrieve the passphrase used to encrypt the block device. */ + const std::string passphrase() const { return this->_pw; } + + static Key *parseFromData(const std::string &, int, int*, int*); + bool validate(ScriptOptions) const override; + bool execute(ScriptOptions) const override; }; class LVMPhysical : public StringKey { diff --git a/hscript/script.cc b/hscript/script.cc index ea083a8..cc819e4 100644 --- a/hscript/script.cc +++ b/hscript/script.cc @@ -123,6 +123,8 @@ struct Script::ScriptPrivate { std::vector< std::unique_ptr<LVMGroup> > lvm_vgs; /*! LVM logical volume keys */ std::vector< std::unique_ptr<LVMVolume> > lvm_lvs; + /*! LUKS creation keys */ + std::vector< std::unique_ptr<Encrypt> > luks; /*! Filesystem creation keys */ std::vector< std::unique_ptr<Filesystem> > fses; /*! Target system's mountpoints. */ @@ -211,6 +213,10 @@ struct Script::ScriptPrivate { std::unique_ptr<LVMVolume> lv(dynamic_cast<LVMVolume *>(obj)); this->lvm_lvs.push_back(std::move(lv)); return true; + } else if(key_name == "encrypt") { + std::unique_ptr<Encrypt> e(dynamic_cast<Encrypt *>(obj)); + this->luks.push_back(std::move(e)); + return true; } else if(key_name == "fs") { std::unique_ptr<Filesystem> fs(dynamic_cast<Filesystem *>(obj)); this->fses.push_back(std::move(fs)); @@ -706,7 +712,8 @@ bool add_default_repos(std::vector<std::unique_ptr<Keys::Repository>> &repos) { bool Script::validate() const { int failures = 0; std::set<std::string> seen_diskids, seen_labels, seen_parts, seen_pvs, - seen_vg_names, seen_vg_pvs, seen_lvs, seen_fses, seen_mounts; + seen_vg_names, seen_vg_pvs, seen_lvs, seen_fses, seen_mounts, + seen_luks; std::map<const std::string, int> seen_iface; #ifdef HAS_INSTALL_ENV error_code ec; @@ -1004,6 +1011,30 @@ bool Script::validate() const { " does not exist");\ } + /* REQ: Runner.Validate.encrypt */ + for(auto &crypt : this->internal->luks) { + if(!crypt->validate(this->opts)) { + failures++; + continue; + } + + /* REQ: Runner.Validate.encrypt.Unique */ + if(seen_luks.find(crypt->device()) != seen_luks.end()) { + failures++; + output_error("installfile:" + std::to_string(crypt->lineno()), + "encrypt: encryption is already scheduled for " + + crypt->device()); + } + seen_luks.insert(crypt->device()); + + /* REQ: Runner.Validate.encrypt.Block */ + if(opts.test(InstallEnvironment)) { +#ifdef HAS_INSTALL_ENV + CHECK_EXIST_PART_LV(crypt->device(), "encrypt", crypt->lineno()) +#endif /* HAS_INSTALL_ENV */ + } + } + /* REQ: Runner.Validate.fs */ for(auto &fs : this->internal->fses) { if(!fs->validate(this->opts)) { diff --git a/tests/fixtures/0189-encrypt-basic.installfile b/tests/fixtures/0189-encrypt-basic.installfile new file mode 100644 index 0000000..e198832 --- /dev/null +++ b/tests/fixtures/0189-encrypt-basic.installfile @@ -0,0 +1,9 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +diskid /dev/sdb WDBNCE2500PNC +disklabel /dev/sdb gpt +partition /dev/sdb 1 fill +encrypt /dev/sdb1 +mount /dev/sdb1 / diff --git a/tests/fixtures/0190-encrypt-duplicate.installfile b/tests/fixtures/0190-encrypt-duplicate.installfile new file mode 100644 index 0000000..72eafec --- /dev/null +++ b/tests/fixtures/0190-encrypt-duplicate.installfile @@ -0,0 +1,10 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +diskid /dev/sdb WDBNCE2500PNC +disklabel /dev/sdb gpt +partition /dev/sdb 1 fill +encrypt /dev/sdb1 +encrypt /dev/sdb1 +mount /dev/sdb1 / diff --git a/tests/fixtures/0191-encrypt-invalid.installfile b/tests/fixtures/0191-encrypt-invalid.installfile new file mode 100644 index 0000000..fc0c06f --- /dev/null +++ b/tests/fixtures/0191-encrypt-invalid.installfile @@ -0,0 +1,9 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +diskid /dev/sdb WDBNCE2500PNC +disklabel /dev/sdb gpt +partition /dev/sdb 1 fill +encrypt sdb1 +mount /dev/sdb1 / diff --git a/tests/fixtures/0192-encrypt-pw.installfile b/tests/fixtures/0192-encrypt-pw.installfile new file mode 100644 index 0000000..29612e4 --- /dev/null +++ b/tests/fixtures/0192-encrypt-pw.installfile @@ -0,0 +1,9 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +diskid /dev/sdb WDBNCE2500PNC +disklabel /dev/sdb gpt +partition /dev/sdb 1 fill +encrypt /dev/sdb1 shhsekrit +mount /dev/sdb1 / diff --git a/tests/spec/validator_spec.rb b/tests/spec/validator_spec.rb index 5c78f36..a9c5fd9 100644 --- a/tests/spec/validator_spec.rb +++ b/tests/spec/validator_spec.rb @@ -910,6 +910,30 @@ RSpec.describe 'HorizonScript validation', :type => :aruba do expect(last_command_started).to have_output(/error: .*lvm_lv.*volume group/) end end + context "for 'encrypt' key" do + it "succeeds with a simple value" do + use_fixture '0189-encrypt-basic.installfile' + run_validate + expect(last_command_started).to have_output(PARSER_SUCCESS) + expect(last_command_started).to have_output(VALIDATOR_SUCCESS) + end + it "fails with a duplicate block device" do + use_fixture '0190-encrypt-duplicate.installfile' + run_validate + expect(last_command_started).to have_output(/error: .*encrypt.*already/) + end + it "fails with an invalid block device" do + use_fixture '0191-encrypt-invalid.installfile' + run_validate + expect(last_command_started).to have_output(/error: .*encrypt.*expected/) + end + it "succeeds with a passphrase" do + use_fixture '0192-encrypt-pw.installfile' + run_validate + expect(last_command_started).to have_output(PARSER_SUCCESS) + expect(last_command_started).to have_output(VALIDATOR_SUCCESS) + end + end context "for 'fs' key" do it "succeeds with a simple value" do use_fixture '0179-fs-basic.installfile' |