From: Kees Monshouwer Date: Sun, 26 Jun 2022 22:38:11 +0000 (+0200) Subject: auth: add options to DomainInfo X-Git-Tag: auth-4.8.0-alpha0~7^2~28 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9da0c59630ea98eec753ee3f18abc15e26d9bc6b;p=thirdparty%2Fpdns.git auth: add options to DomainInfo --- diff --git a/modules/gmysqlbackend/4.3.0_to_4.7.0_schema.mysql.sql b/modules/gmysqlbackend/4.3.0_to_4.7.0_schema.mysql.sql new file mode 100644 index 0000000000..97fd3c465f --- /dev/null +++ b/modules/gmysqlbackend/4.3.0_to_4.7.0_schema.mysql.sql @@ -0,0 +1 @@ +ALTER TABLE domains ADD options VARCHAR(64000) DEFAULT NULL AFTER notified_serial; diff --git a/modules/gmysqlbackend/gmysqlbackend.cc b/modules/gmysqlbackend/gmysqlbackend.cc index fcea02024c..0b6073a6d3 100644 --- a/modules/gmysqlbackend/gmysqlbackend.cc +++ b/modules/gmysqlbackend/gmysqlbackend.cc @@ -101,7 +101,7 @@ public: declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null"); declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=? and name=? and type is null"); - declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,account from domains where name=?"); + declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,options,account from domains where name=?"); declare(suffix, "info-all-slaves-query", "", "select id,name,master,last_check from domains where type='SLAVE'"); declare(suffix, "supermaster-query", "", "select account from supermasters where ip=? and nameserver=?"); @@ -127,6 +127,7 @@ public: declare(suffix, "update-master-query", "", "update domains set master=? where name=?"); declare(suffix, "update-kind-query", "", "update domains set type=? where name=?"); + declare(suffix, "update-options-query", "", "update domains set options=? where name=?"); declare(suffix, "update-account-query", "", "update domains set account=? where name=?"); declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?"); declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?"); diff --git a/modules/gmysqlbackend/schema.mysql.sql b/modules/gmysqlbackend/schema.mysql.sql index c923035ba6..6d7c17890d 100644 --- a/modules/gmysqlbackend/schema.mysql.sql +++ b/modules/gmysqlbackend/schema.mysql.sql @@ -5,6 +5,7 @@ CREATE TABLE domains ( last_check INT DEFAULT NULL, type VARCHAR(6) NOT NULL, notified_serial INT UNSIGNED DEFAULT NULL, + options VARCHAR(64000) DEFAULT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; diff --git a/modules/godbcbackend/4.3.0_to_4.7.0_schema.mssql.sql b/modules/godbcbackend/4.3.0_to_4.7.0_schema.mssql.sql new file mode 100644 index 0000000000..8babd7aa98 --- /dev/null +++ b/modules/godbcbackend/4.3.0_to_4.7.0_schema.mssql.sql @@ -0,0 +1 @@ +ALTER TABLE domains ADD COLUMN options VARCHAR(MAX) DEFAULT NULL; diff --git a/modules/godbcbackend/godbcbackend.cc b/modules/godbcbackend/godbcbackend.cc index 87e7d4d828..055dedf697 100644 --- a/modules/godbcbackend/godbcbackend.cc +++ b/modules/godbcbackend/godbcbackend.cc @@ -81,7 +81,7 @@ public: declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null"); declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=? and name=? and type is null"); - declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,account from domains where name=?"); + declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,options,account from domains where name=?"); declare(suffix, "info-all-slaves-query", "", "select id,name,master,last_check from domains where type='SLAVE'"); declare(suffix, "supermaster-query", "", "select account from supermasters where ip=? and nameserver=?"); @@ -107,6 +107,7 @@ public: declare(suffix, "update-master-query", "", "update domains set master=? where name=?"); declare(suffix, "update-kind-query", "", "update domains set type=? where name=?"); + declare(suffix, "update-options-query", "", "update domains set options=? where name=?"); declare(suffix, "update-account-query", "", "update domains set account=? where name=?"); declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?"); declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?"); diff --git a/modules/godbcbackend/schema.mssql.sql b/modules/godbcbackend/schema.mssql.sql index d5922dc852..1646d4e665 100644 --- a/modules/godbcbackend/schema.mssql.sql +++ b/modules/godbcbackend/schema.mssql.sql @@ -5,6 +5,7 @@ CREATE TABLE domains ( last_check INT DEFAULT NULL, type VARCHAR(6) NOT NULL, notified_serial INT DEFAULT NULL, + options VARCHAR(MAX) DEFAULT NULL, account VARCHAR(40) DEFAULT NULL, PRIMARY KEY (id) ); diff --git a/modules/gpgsqlbackend/4.3.0_to_4.7.0_schema.pgsql.sql b/modules/gpgsqlbackend/4.3.0_to_4.7.0_schema.pgsql.sql new file mode 100644 index 0000000000..ed9b6e2faa --- /dev/null +++ b/modules/gpgsqlbackend/4.3.0_to_4.7.0_schema.pgsql.sql @@ -0,0 +1,8 @@ +BEGIN; + ALTER TABLE domains ADD COLUMN options VARCHAR(65535) DEFAULT NULL; + + ALTER TABLE domains ADD COLUMN account_new VARCHAR(40) DEFAULT NULL; + UPDATE domains SET account_new = account; + ALTER TABLE domains DROP COLUMN account; + ALTER TABLE domains RENAME COLUMN account_new TO account; +COMMIT; diff --git a/modules/gpgsqlbackend/gpgsqlbackend.cc b/modules/gpgsqlbackend/gpgsqlbackend.cc index 906fa81282..2f7598e933 100644 --- a/modules/gpgsqlbackend/gpgsqlbackend.cc +++ b/modules/gpgsqlbackend/gpgsqlbackend.cc @@ -108,7 +108,7 @@ public: declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=$1 and type is null"); declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=$1 and name=$2 and type is null"); - declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,account from domains where name=$1"); + declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,options,account from domains where name=$1"); declare(suffix, "info-all-slaves-query", "", "select id,name,master,last_check from domains where type='SLAVE'"); declare(suffix, "supermaster-query", "", "select account from supermasters where ip=$1 and nameserver=$2"); @@ -134,6 +134,7 @@ public: declare(suffix, "update-master-query", "", "update domains set master=$1 where name=$2"); declare(suffix, "update-kind-query", "", "update domains set type=$1 where name=$2"); + declare(suffix, "update-options-query", "", "update domains set options=$1 where name=$2"); declare(suffix, "update-account-query", "", "update domains set account=$1 where name=$2"); declare(suffix, "update-serial-query", "", "update domains set notified_serial=$1 where id=$2"); declare(suffix, "update-lastcheck-query", "", "update domains set last_check=$1 where id=$2"); diff --git a/modules/gpgsqlbackend/schema.pgsql.sql b/modules/gpgsqlbackend/schema.pgsql.sql index 80735c2e6b..29bb1793b5 100644 --- a/modules/gpgsqlbackend/schema.pgsql.sql +++ b/modules/gpgsqlbackend/schema.pgsql.sql @@ -5,6 +5,7 @@ CREATE TABLE domains ( last_check INT DEFAULT NULL, type VARCHAR(6) NOT NULL, notified_serial BIGINT DEFAULT NULL, + options VARCHAR(65535) DEFAULT NULL; account VARCHAR(40) DEFAULT NULL, CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) ); diff --git a/modules/gsqlite3backend/4.3.1_to_4.7.0_schema.sqlite3.sql b/modules/gsqlite3backend/4.3.1_to_4.7.0_schema.sqlite3.sql new file mode 100644 index 0000000000..32374d5ca2 --- /dev/null +++ b/modules/gsqlite3backend/4.3.1_to_4.7.0_schema.sqlite3.sql @@ -0,0 +1,24 @@ +PRAGMA foreign_keys = 0; + +BEGIN TRANSACTION; + CREATE TABLE domains_temp ( + id INTEGER PRIMARY KEY, + name VARCHAR(255) NOT NULL COLLATE NOCASE, + master VARCHAR(128) DEFAULT NULL, + last_check INTEGER DEFAULT NULL, + type VARCHAR(6) NOT NULL, + notified_serial INTEGER DEFAULT NULL, + options VARCHAR(65535) DEFAULT NULL, + account VARCHAR(40) DEFAULT NULL + ); + + INSERT INTO domains_temp SELECT id,name,master,last_check,type,motified_serial,NULL,account FROM domains; + DROP TABLE domains; + ALTER TABLE domains_temp RENAME TO domains; + + CREATE UNIQUE INDEX name_index ON domains(name); +COMMIT; + +PRAGMA foreign_keys = 1; + +ANALYZE; diff --git a/modules/gsqlite3backend/gsqlite3backend.cc b/modules/gsqlite3backend/gsqlite3backend.cc index fd50ddcb60..55d9f387ac 100644 --- a/modules/gsqlite3backend/gsqlite3backend.cc +++ b/modules/gsqlite3backend/gsqlite3backend.cc @@ -94,7 +94,7 @@ public: declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=:domain_id and type is null"); declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=:domain_id and name=:qname and type is null"); - declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,account from domains where name=:domain"); + declare(suffix, "info-zone-query", "", "select id,name,master,last_check,notified_serial,type,options,account from domains where name=:domain"); declare(suffix, "info-all-slaves-query", "", "select id,name,master,last_check from domains where type='SLAVE'"); declare(suffix, "supermaster-query", "", "select account from supermasters where ip=:ip and nameserver=:nameserver"); @@ -120,6 +120,7 @@ public: declare(suffix, "update-master-query", "", "update domains set master=:master where name=:domain"); declare(suffix, "update-kind-query", "", "update domains set type=:kind where name=:domain"); + declare(suffix, "update-options-query", "", "update domains set options=:options where name=:domain"); declare(suffix, "update-account-query", "", "update domains set account=:account where name=:domain"); declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id"); declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id"); diff --git a/modules/gsqlite3backend/schema.sqlite3.sql b/modules/gsqlite3backend/schema.sqlite3.sql index 0875521185..5067320755 100644 --- a/modules/gsqlite3backend/schema.sqlite3.sql +++ b/modules/gsqlite3backend/schema.sqlite3.sql @@ -6,6 +6,7 @@ CREATE TABLE domains ( master VARCHAR(128) DEFAULT NULL, last_check INTEGER DEFAULT NULL, type VARCHAR(6) NOT NULL, + options VARCHAR(65535) DEFAULT NULL, notified_serial INTEGER DEFAULT NULL, account VARCHAR(40) DEFAULT NULL ); diff --git a/modules/lmdbbackend/lmdbbackend.cc b/modules/lmdbbackend/lmdbbackend.cc index bab1926963..ae620a295e 100644 --- a/modules/lmdbbackend/lmdbbackend.cc +++ b/modules/lmdbbackend/lmdbbackend.cc @@ -53,6 +53,7 @@ // List the class version here. Default is 0 BOOST_CLASS_VERSION(LMDBBackend::KeyDataDB, 1) +BOOST_CLASS_VERSION(DomainInfo, 1) static bool s_first = true; static int s_shards = 0; @@ -191,7 +192,7 @@ namespace serialization } template - void serialize(Archive& ar, DomainInfo& g, const unsigned int version) + void save(Archive& ar, const DomainInfo& g, const unsigned int version) { ar& g.zone; ar& g.last_check; @@ -200,6 +201,25 @@ namespace serialization ar& g.id; ar& g.notified_serial; ar& g.kind; + ar& g.options; + } + + template + void load(Archive& ar, DomainInfo& g, const unsigned int version) + { + ar& g.zone; + ar& g.last_check; + ar& g.account; + ar& g.masters; + ar& g.id; + ar& g.notified_serial; + ar& g.kind; + if (version >= 1) { + ar& g.options; + } + else { + g.options.clear(); + } } template @@ -240,6 +260,7 @@ namespace serialization BOOST_SERIALIZATION_SPLIT_FREE(DNSName); BOOST_SERIALIZATION_SPLIT_FREE(QType); BOOST_SERIALIZATION_SPLIT_FREE(LMDBBackend::KeyDataDB); +BOOST_SERIALIZATION_SPLIT_FREE(DomainInfo); BOOST_IS_BITWISE_SERIALIZABLE(ComboAddress); template <> @@ -953,6 +974,13 @@ bool LMDBBackend::setKind(const DNSName& domain, const DomainInfo::DomainKind ki }); } +bool LMDBBackend::setOptions(const DNSName& domain, const std::string& options) +{ + return genChangeDomain(domain, [options](DomainInfo& di) { + di.options = options; + }); +} + bool LMDBBackend::setAccount(const DNSName& domain, const std::string& account) { return genChangeDomain(domain, [account](DomainInfo& di) { diff --git a/modules/lmdbbackend/lmdbbackend.hh b/modules/lmdbbackend/lmdbbackend.hh index 99244a9ef8..70f9e54922 100644 --- a/modules/lmdbbackend/lmdbbackend.hh +++ b/modules/lmdbbackend/lmdbbackend.hh @@ -106,6 +106,7 @@ public: void setStale(uint32_t domain_id) override; void setFresh(uint32_t domain_id) override; void setNotified(uint32_t id, uint32_t serial) override; + bool setOptions(const DNSName& domain, const std::string& options) override; bool setAccount(const DNSName& domain, const std::string& account) override; bool deleteDomain(const DNSName& domain) override; diff --git a/pdns/backends/gsql/gsqlbackend.cc b/pdns/backends/gsql/gsqlbackend.cc index ab8ef9f5b0..0f4241c733 100644 --- a/pdns/backends/gsql/gsqlbackend.cc +++ b/pdns/backends/gsql/gsqlbackend.cc @@ -79,6 +79,7 @@ GSQLBackend::GSQLBackend(const string &mode, const string &suffix) d_UpdateKindOfZoneQuery=getArg("update-kind-query"); d_UpdateSerialOfZoneQuery=getArg("update-serial-query"); d_UpdateLastCheckOfZoneQuery=getArg("update-lastcheck-query"); + d_UpdateOptionsOfZoneQuery = getArg("update-options-query"); d_UpdateAccountOfZoneQuery=getArg("update-account-query"); d_InfoOfAllMasterDomainsQuery=getArg("info-all-master-query"); d_DeleteDomainQuery=getArg("delete-domain-query"); @@ -152,6 +153,7 @@ GSQLBackend::GSQLBackend(const string &mode, const string &suffix) d_UpdateKindOfZoneQuery_stmt = nullptr; d_UpdateSerialOfZoneQuery_stmt = nullptr; d_UpdateLastCheckOfZoneQuery_stmt = nullptr; + d_UpdateOptionsOfZoneQuery_stmt = nullptr; d_UpdateAccountOfZoneQuery_stmt = nullptr; d_InfoOfAllMasterDomainsQuery_stmt = nullptr; d_DeleteDomainQuery_stmt = nullptr; @@ -275,6 +277,25 @@ bool GSQLBackend::setKind(const DNSName &domain, const DomainInfo::DomainKind ki return true; } +bool GSQLBackend::setOptions(const DNSName& domain, const string& options) +{ + try { + reconnectIfNeeded(); + + // clang-format off + d_UpdateOptionsOfZoneQuery_stmt-> + bind("options", options)-> + bind("domain", domain)-> + execute()-> + reset(); + // clang-format on + } + catch (SSqlException& e) { + throw PDNSException("GSQLBackend unable to set options of domain '" + domain.toLogString() + "' to '" + options + "': " + e.txtReason()); + } + return true; +} + bool GSQLBackend::setAccount(const DNSName &domain, const string &account) { try { @@ -313,7 +334,7 @@ bool GSQLBackend::getDomainInfo(const DNSName &domain, DomainInfo &di, bool getS if(!numanswers) return false; - ASSERT_ROW_COLUMNS("info-zone-query", d_result[0], 7); + ASSERT_ROW_COLUMNS("info-zone-query", d_result[0], 8); pdns::checked_stoi_into(di.id, d_result[0][0]); try { @@ -322,7 +343,8 @@ bool GSQLBackend::getDomainInfo(const DNSName &domain, DomainInfo &di, bool getS return false; } string type=d_result[0][5]; - di.account=d_result[0][6]; + di.options = d_result[0][6]; + di.account = d_result[0][7]; di.kind = DomainInfo::stringToKind(type); vector masters; diff --git a/pdns/backends/gsql/gsqlbackend.hh b/pdns/backends/gsql/gsqlbackend.hh index 365fd69a8a..dbe02aac61 100644 --- a/pdns/backends/gsql/gsqlbackend.hh +++ b/pdns/backends/gsql/gsqlbackend.hh @@ -74,6 +74,7 @@ protected: d_InsertEmptyNonTerminalOrderQuery_stmt = d_db->prepare(d_InsertEmptyNonTerminalOrderQuery, 4); d_UpdateMasterOfZoneQuery_stmt = d_db->prepare(d_UpdateMasterOfZoneQuery, 2); d_UpdateKindOfZoneQuery_stmt = d_db->prepare(d_UpdateKindOfZoneQuery, 2); + d_UpdateOptionsOfZoneQuery_stmt = d_db->prepare(d_UpdateOptionsOfZoneQuery, 2); d_UpdateAccountOfZoneQuery_stmt = d_db->prepare(d_UpdateAccountOfZoneQuery, 2); d_UpdateSerialOfZoneQuery_stmt = d_db->prepare(d_UpdateSerialOfZoneQuery, 2); d_UpdateLastCheckOfZoneQuery_stmt = d_db->prepare(d_UpdateLastCheckOfZoneQuery, 2); @@ -140,6 +141,7 @@ protected: d_InsertEmptyNonTerminalOrderQuery_stmt.reset(); d_UpdateMasterOfZoneQuery_stmt.reset(); d_UpdateKindOfZoneQuery_stmt.reset(); + d_UpdateOptionsOfZoneQuery_stmt.reset(); d_UpdateAccountOfZoneQuery_stmt.reset(); d_UpdateSerialOfZoneQuery_stmt.reset(); d_UpdateLastCheckOfZoneQuery_stmt.reset(); @@ -212,6 +214,7 @@ public: void setNotified(uint32_t domain_id, uint32_t serial) override; bool setMasters(const DNSName &domain, const vector &masters) override; bool setKind(const DNSName &domain, const DomainInfo::DomainKind kind) override; + bool setOptions(const DNSName& domain, const string& options) override; bool setAccount(const DNSName &domain, const string &account) override; bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) override; @@ -303,6 +306,7 @@ private: string d_InsertEmptyNonTerminalOrderQuery; string d_UpdateMasterOfZoneQuery; string d_UpdateKindOfZoneQuery; + string d_UpdateOptionsOfZoneQuery; string d_UpdateAccountOfZoneQuery; string d_UpdateSerialOfZoneQuery; string d_UpdateLastCheckOfZoneQuery; @@ -376,6 +380,7 @@ private: unique_ptr d_InsertEmptyNonTerminalOrderQuery_stmt; unique_ptr d_UpdateMasterOfZoneQuery_stmt; unique_ptr d_UpdateKindOfZoneQuery_stmt; + unique_ptr d_UpdateOptionsOfZoneQuery_stmt; unique_ptr d_UpdateAccountOfZoneQuery_stmt; unique_ptr d_UpdateSerialOfZoneQuery_stmt; unique_ptr d_UpdateLastCheckOfZoneQuery_stmt; diff --git a/pdns/dnsbackend.hh b/pdns/dnsbackend.hh index 84689c8087..a73d4438df 100644 --- a/pdns/dnsbackend.hh +++ b/pdns/dnsbackend.hh @@ -50,6 +50,7 @@ struct DomainInfo DNSName zone; time_t last_check; + string options; string account; vector masters; DNSBackend *backend; @@ -349,6 +350,12 @@ public: return false; } + //! Called when the options of a domain should be changed + virtual bool setOptions(const DNSName& domain, const string& options) + { + return false; + } + //! Called when the Account of a domain should be changed virtual bool setAccount(const DNSName &domain, const string &account) { diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index 6e7066b784..75826d1774 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -15,6 +15,7 @@ #include #include #include +#include "json11.hpp" #include "tsigutils.hh" #include "dnsbackend.hh" #include "ueberbackend.hh" @@ -1858,6 +1859,22 @@ static bool disableDNSSECOnZone(DNSSECKeeper& dk, const DNSName& zone) return ret; } +static int setZoneOptions(const DNSName& zone, const string& options) +{ + UeberBackend B("default"); + DomainInfo di; + + if (!B.getDomainInfo(zone, di)) { + cerr << "No such zone " << zone << " in the database" << endl; + return EXIT_FAILURE; + } + if (!di.backend->setOptions(zone, options)) { + cerr << "Could not find backend willing to accept new zone configuration" << endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + static int setZoneAccount(const DNSName& zone, const string &account) { UeberBackend B("default"); @@ -2101,6 +2118,10 @@ static bool showZone(DNSSECKeeper& dk, const DNSName& zone, bool exportDS = fals } } } + if (!di.options.empty()) { + cout << "Options:" << endl; + cout << di.options << endl; + } return true; } @@ -2464,6 +2485,7 @@ try cout << "secure-all-zones [increase-serial] Secure all zones without keys" << endl; cout << "secure-zone ZONE [ZONE ..] Add DNSSEC to zone ZONE" << endl; cout << "set-kind ZONE KIND Change the kind of ZONE to KIND (primary, secondary, native)" << endl; + cout << "set-options ZONE OPTIONS Change the options of ZONE to OPTIONS" << endl; cout << "set-account ZONE ACCOUNT Change the account (owner) of ZONE to ACCOUNT" << endl; cout << "set-nsec3 ZONE ['PARAMS' [narrow]] Enable NSEC3 with PARAMS. Optionally narrow" << endl; cout << "set-presigned ZONE Use presigned RRSIGs from storage" << endl; @@ -3110,6 +3132,21 @@ try auto kind = DomainInfo::stringToKind(cmds.at(2)); return setZoneKind(zone, kind); } + else if (cmds.at(0) == "set-options") { + if (cmds.size() != 3) { + cerr << "Syntax: pdnsutil set-options ZONE OPTIONS" << endl; + return 0; + } + // Verify json + std::string err; + json11::Json doc = json11::Json::parse(cmds.at(2), err); + if (doc.is_null()) { + cerr << "Parsing of JSON document failed:" << err << endl; + return EXIT_FAILURE; + } + DNSName zone(cmds.at(1)); + return setZoneOptions(zone, cmds.at(2)); + } else if (cmds.at(0) == "set-account") { if(cmds.size() != 3) { cerr<<"Syntax: pdnsutil set-account ZONE ACCOUNT"<