Aktualizr
C++ SOTA Client
config.cc
1 #include "config.h"
2 
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <iomanip>
6 #include <sstream>
7 
8 #include "bootstrap/bootstrap.h"
9 #include "config.h"
10 #include "utilities/exceptions.h"
11 #include "utilities/utils.h"
12 
13 void NetworkConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
14  CopyFromConfig(ipdiscovery_host, "ipdiscovery_host", pt);
15  CopyFromConfig(ipdiscovery_port, "ipdiscovery_port", pt);
16  CopyFromConfig(ipdiscovery_wait_seconds, "ipdiscovery_wait_seconds", pt);
17  CopyFromConfig(ipuptane_port, "ipuptane_port", pt);
18 }
19 
20 void NetworkConfig::writeToStream(std::ostream& out_stream) const {
21  writeOption(out_stream, ipdiscovery_host, "ipdiscovery_host");
22  writeOption(out_stream, ipdiscovery_port, "ipdiscovery_port");
23  writeOption(out_stream, ipdiscovery_wait_seconds, "ipdiscovery_wait_seconds");
24  writeOption(out_stream, ipuptane_port, "ipuptane_port");
25 }
26 
27 void TlsConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
28  CopyFromConfig(server, "server", pt);
29  CopyFromConfig(server_url_path, "server_url_path", pt);
30  CopyFromConfig(ca_source, "ca_source", pt);
31  CopyFromConfig(cert_source, "cert_source", pt);
32  CopyFromConfig(pkey_source, "pkey_source", pt);
33 }
34 
35 void TlsConfig::writeToStream(std::ostream& out_stream) const {
36  writeOption(out_stream, server, "server");
37  writeOption(out_stream, server_url_path, "server_url_path");
38  writeOption(out_stream, ca_source, "ca_source");
39  writeOption(out_stream, pkey_source, "pkey_source");
40  writeOption(out_stream, cert_source, "cert_source");
41 }
42 
43 void ProvisionConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
44  CopyFromConfig(server, "server", pt);
45  CopyFromConfig(p12_password, "p12_password", pt);
46  CopyFromConfig(expiry_days, "expiry_days", pt);
47  CopyFromConfig(provision_path, "provision_path", pt);
48  CopyFromConfig(device_id, "device_id", pt);
49  CopyFromConfig(primary_ecu_serial, "primary_ecu_serial", pt);
50  CopyFromConfig(primary_ecu_hardware_id, "primary_ecu_hardware_id", pt);
51  CopyFromConfig(ecu_registration_endpoint, "ecu_registration_endpoint", pt);
52  // provision.mode is set in postUpdateValues.
53 }
54 
55 void ProvisionConfig::writeToStream(std::ostream& out_stream) const {
56  writeOption(out_stream, server, "server");
57  writeOption(out_stream, p12_password, "p12_password");
58  writeOption(out_stream, expiry_days, "expiry_days");
59  writeOption(out_stream, provision_path, "provision_path");
60  writeOption(out_stream, device_id, "device_id");
61  writeOption(out_stream, primary_ecu_serial, "primary_ecu_serial");
62  writeOption(out_stream, primary_ecu_hardware_id, "primary_ecu_hardware_id");
63  writeOption(out_stream, ecu_registration_endpoint, "ecu_registration_endpoint");
64  // Skip provision.mode since it is dependent on other options.
65 }
66 
67 void UptaneConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
68  CopyFromConfig(running_mode, "running_mode", pt);
69  CopyFromConfig(polling_sec, "polling_sec", pt);
70  CopyFromConfig(director_server, "director_server", pt);
71  CopyFromConfig(repo_server, "repo_server", pt);
72  CopyFromConfig(key_source, "key_source", pt);
73  CopyFromConfig(key_type, "key_type", pt);
74  CopyFromConfig(secondary_configs_dir, "secondary_configs_dir", pt);
75  // uptane.secondary_configs is populated by processing secondary_configs_dir
76 }
77 
78 void UptaneConfig::writeToStream(std::ostream& out_stream) const {
79  writeOption(out_stream, StringFromRunningMode(running_mode), "running_mode");
80  writeOption(out_stream, polling_sec, "polling_sec");
81  writeOption(out_stream, director_server, "director_server");
82  writeOption(out_stream, repo_server, "repo_server");
83  writeOption(out_stream, key_source, "key_source");
84  writeOption(out_stream, key_type, "key_type");
85  writeOption(out_stream, secondary_configs_dir, "secondary_configs_dir");
86 }
87 
88 void DiscoveryConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
89  CopyFromConfig(ipuptane, "ipuptane", pt);
90 }
91 
92 void DiscoveryConfig::writeToStream(std::ostream& out_stream) const { writeOption(out_stream, ipuptane, "ipuptane"); }
93 
94 /**
95  * \par Description:
96  * Overload the << operator for the configuration class allowing
97  * us to print its content, i.e. for logging purposes.
98  */
99 std::ostream& operator<<(std::ostream& os, const Config& cfg) {
100  cfg.writeToStream(os);
101  return os;
102 }
103 
104 Config::Config() { postUpdateValues(); }
105 
106 Config::Config(const boost::filesystem::path& filename) {
107  updateFromToml(filename);
108  postUpdateValues();
109 }
110 
111 Config::Config(const std::vector<boost::filesystem::path>& config_dirs) {
112  checkDirs(config_dirs);
113  updateFromDirs(config_dirs);
114  postUpdateValues();
115 }
116 
117 Config::Config(const boost::program_options::variables_map& cmd) {
118  // Redundantly check and set the loglevel from the commandline prematurely so
119  // that it is taken account while processing the config.
120  if (cmd.count("loglevel") != 0) {
121  logger.loglevel = cmd["loglevel"].as<int>();
122  logger_set_threshold(logger);
123  loglevel_from_cmdline = true;
124  }
125 
126  if (cmd.count("config") > 0) {
127  const auto configs = cmd["config"].as<std::vector<boost::filesystem::path>>();
128  checkDirs(configs);
129  updateFromDirs(configs);
130  } else {
131  updateFromDirs(config_dirs_);
132  }
133  updateFromCommandLine(cmd);
134  postUpdateValues();
135 }
136 
137 KeyManagerConfig Config::keymanagerConfig() const {
138  return KeyManagerConfig{p11, tls.ca_source, tls.pkey_source, tls.cert_source, uptane.key_type, uptane.key_source};
139 }
140 
141 void Config::postUpdateValues() {
142  logger_set_threshold(logger);
143 
144  if (provision.provision_path.empty()) {
145  provision.mode = ProvisionMode::kImplicit;
146  }
147 
148  if (tls.server.empty()) {
149  if (!tls.server_url_path.empty()) {
150  try {
151  tls.server = Utils::readFile(tls.server_url_path, true);
152  } catch (const boost::filesystem::filesystem_error& e) {
153  LOG_ERROR << "Couldn't read gateway URL: " << e.what();
154  tls.server = "";
155  }
156  } else if (!provision.provision_path.empty()) {
157  if (boost::filesystem::exists(provision.provision_path)) {
158  tls.server = Bootstrap::readServerUrl(provision.provision_path);
159  } else {
160  LOG_ERROR << "Provided provision archive " << provision.provision_path << " does not exist!";
161  }
162  }
163  }
164 
165  if (!tls.server.empty()) {
166  if (provision.server.empty()) {
167  provision.server = tls.server;
168  }
169 
170  if (uptane.repo_server.empty()) {
171  uptane.repo_server = tls.server + "/repo";
172  }
173 
174  if (uptane.director_server.empty()) {
175  uptane.director_server = tls.server + "/director";
176  }
177 
178  if (pacman.ostree_server.empty()) {
179  pacman.ostree_server = tls.server + "/treehub";
180  }
181  }
182 
183  if (!uptane.director_server.empty()) {
184  if (provision.ecu_registration_endpoint.empty()) {
185  provision.ecu_registration_endpoint = uptane.director_server + "/ecus";
186  }
187  }
188 
189  if (!uptane.secondary_configs_dir.empty()) {
190  readSecondaryConfigs(uptane.secondary_configs_dir);
191  }
192 
193  LOG_TRACE << "Final configuration that will be used: \n" << (*this);
194 }
195 
196 // For testing
197 void Config::updateFromTomlString(const std::string& contents) {
198  boost::property_tree::ptree pt;
199  std::stringstream stream(contents);
200  boost::property_tree::ini_parser::read_ini(stream, pt);
201  updateFromPropertyTree(pt);
202 }
203 
204 void Config::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
205  // Keep this order the same as in config.h and Config::writeToStream().
206  if (!loglevel_from_cmdline) {
207  CopySubtreeFromConfig(logger, "logger", pt);
208  // If not already set from the commandline, set the loglevel now so that it
209  // affects the rest of the config processing.
210  logger_set_threshold(logger);
211  }
212  CopySubtreeFromConfig(network, "network", pt);
213  CopySubtreeFromConfig(p11, "p11", pt);
214  CopySubtreeFromConfig(tls, "tls", pt);
215  CopySubtreeFromConfig(provision, "provision", pt);
216  CopySubtreeFromConfig(uptane, "uptane", pt);
217  CopySubtreeFromConfig(discovery, "discovery", pt);
218  CopySubtreeFromConfig(pacman, "pacman", pt);
219  CopySubtreeFromConfig(storage, "storage", pt);
220  CopySubtreeFromConfig(import, "import", pt);
221  CopySubtreeFromConfig(telemetry, "telemetry", pt);
222  CopySubtreeFromConfig(bootloader, "bootloader", pt);
223 }
224 
225 void Config::updateFromCommandLine(const boost::program_options::variables_map& cmd) {
226  // Try to keep these options in the same order as parse_options() in main.cc.
227  if (cmd.count("loglevel") != 0) {
228  logger.loglevel = cmd["loglevel"].as<int>();
229  }
230  if (cmd.count("running-mode") != 0) {
231  uptane.running_mode = RunningModeFromString(cmd["running-mode"].as<std::string>());
232  }
233  if (cmd.count("tls-server") != 0) {
234  tls.server = cmd["tls-server"].as<std::string>();
235  }
236  if (cmd.count("repo-server") != 0) {
237  uptane.repo_server = cmd["repo-server"].as<std::string>();
238  }
239  if (cmd.count("director-server") != 0) {
240  uptane.director_server = cmd["director-server"].as<std::string>();
241  }
242  if (cmd.count("ostree-server") != 0) {
243  pacman.ostree_server = cmd["ostree-server"].as<std::string>();
244  }
245  if (cmd.count("primary-ecu-serial") != 0) {
246  provision.primary_ecu_serial = cmd["primary-ecu-serial"].as<std::string>();
247  }
248  if (cmd.count("primary-ecu-hardware-id") != 0) {
249  provision.primary_ecu_hardware_id = cmd["primary-ecu-hardware-id"].as<std::string>();
250  }
251  if (cmd.count("secondary-configs-dir") != 0) {
252  uptane.secondary_configs_dir = cmd["secondary-configs-dir"].as<boost::filesystem::path>();
253  }
254 }
255 
256 void Config::readSecondaryConfigs(const boost::filesystem::path& sconfigs_dir) {
257  if (!boost::filesystem::is_directory(sconfigs_dir)) {
258  LOG_ERROR << "Could not read secondary configs from " << sconfigs_dir << ": not a directory";
259  return;
260  }
261  for (const auto& config_file : Utils::glob((sconfigs_dir / "*.json").string())) {
262  LOG_INFO << "Parsing secondary config: " << config_file;
263  uptane.secondary_configs.emplace_back(config_file);
264  }
265 }
266 
267 void Config::writeToStream(std::ostream& sink) const {
268  // Keep this order the same as in config.h and
269  // Config::updateFromPropertyTree().
270  WriteSectionToStream(logger, "logger", sink);
271  WriteSectionToStream(network, "network", sink);
272  WriteSectionToStream(p11, "p11", sink);
273  WriteSectionToStream(tls, "tls", sink);
274  WriteSectionToStream(provision, "provision", sink);
275  WriteSectionToStream(uptane, "uptane", sink);
276  WriteSectionToStream(discovery, "discovery", sink);
277  WriteSectionToStream(pacman, "pacman", sink);
278  WriteSectionToStream(storage, "storage", sink);
279  WriteSectionToStream(import, "import", sink);
280  WriteSectionToStream(telemetry, "telemetry", sink);
281  WriteSectionToStream(bootloader, "bootloader", sink);
282 }
283 
284 asn1::Serializer& operator<<(asn1::Serializer& ser, CryptoSource cs) {
285  ser << asn1::implicit<kAsn1Enum>(static_cast<const int32_t&>(static_cast<int>(cs)));
286 
287  return ser;
288 }
289 
290 asn1::Serializer& operator<<(asn1::Serializer& ser, const TlsConfig& tls_conf) {
291  ser << asn1::seq << asn1::implicit<kAsn1Utf8String>(tls_conf.server)
292  << asn1::implicit<kAsn1Utf8String>(tls_conf.server_url_path.string()) << tls_conf.ca_source
293  << tls_conf.pkey_source << tls_conf.cert_source << asn1::endseq;
294  return ser;
295 }
296 
297 asn1::Deserializer& operator>>(asn1::Deserializer& des, CryptoSource& cs) {
298  int32_t cs_i;
299  des >> asn1::implicit<kAsn1Enum>(cs_i);
300 
301  if (cs_i < static_cast<int>(CryptoSource::kFile) || cs_i > static_cast<int>(CryptoSource::kPkcs11)) {
302  throw deserialization_error();
303  }
304 
305  cs = static_cast<CryptoSource>(cs_i);
306 
307  return des;
308 }
309 
310 asn1::Deserializer& operator>>(asn1::Deserializer& des, boost::filesystem::path& path) {
311  std::string path_string;
312  des >> asn1::implicit<kAsn1Utf8String>(path_string);
313  path = path_string;
314  return des;
315 }
316 
317 asn1::Deserializer& operator>>(asn1::Deserializer& des, TlsConfig& tls_conf) {
318  des >> asn1::seq >> asn1::implicit<kAsn1Utf8String>(tls_conf.server) >> tls_conf.server_url_path >>
319  tls_conf.ca_source >> tls_conf.pkey_source >> tls_conf.cert_source >> asn1::endseq;
320  return des;
321 }
Configuration object for an aktualizr instance running on a primary ECU.
Definition: config.h:97