libdigidocpp
XmlConf.cpp
Go to the documentation of this file.
1 /*
2  * libdigidocpp
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 
20 #include "XmlConf.h"
21 
22 #include "log.h"
23 #include "util/File.h"
24 #include "xml/conf.hxx"
25 
26 #include <xsd/cxx/xml/dom/parsing-source.hxx> //for parsing xml data into DOMDocument
27 
28 #include <iostream>
29 #include <fstream>
30 #ifdef _WIN32
31 #include <windows.h>
32 #elif defined(__APPLE__)
33 #include <CoreFoundation/CoreFoundation.h>
34 #endif
35 
36 namespace digidoc
37 {
38 
39 template <class A>
41 {
42 public:
43  XmlConfParam(): locked(false) {}
44  XmlConfParam(A val): value(val), locked(false) {}
45 
46  void setValue(const A &val, bool lock, bool global)
47  {
48  if(global) locked = lock;
49  if(global || !locked) value = val;
50  }
51 
52  XmlConfParam & operator=( const A &other )
53  {
54  value = other; return *this;
55  }
56 
57  A value;
58  bool locked;
59 };
60 
62 {
63 public:
65 
66  void init(const std::string &path, bool global) throw(IOException);
67  std::auto_ptr<Configuration> read(const std::string &path) throw(IOException);
68 
69  void setUserConf(const std::string &paramName, const std::string &value) throw(IOException);
70  void serializeUserConf(const Configuration &pConf) throw(IOException);
71 
88  std::vector<XmlConf::OCSPConf> ocsp;
89 
90  static std::string DEFAULT_CONF_LOC;
91  static std::string USER_CONF_LOC;
92 
93  static const std::string LOG_LEVEL;
94  static const std::string LOG_FILE;
95  static const std::string DIGEST_URI;
96  static const std::string SIGNATURE_URI;
97  static const std::string PKCS11_DRIVER_PATH;
98  static const std::string CERT_STORE_PATH;
99  static const std::string MANIFEST_XSD_PATH;
100  static const std::string XADES_XSD_PATH;
101  static const std::string DSIG_XSD_PATH;
102  static const std::string PROXY_HOST;
103  static const std::string PROXY_PORT;
104  static const std::string PROXY_USER;
105  static const std::string PROXY_PASS;
106  static const std::string PKCS12_CERT;
107  static const std::string PKCS12_PASS;
108  static const std::string PKCS12_DISABLE;
109 };
110 }
111 
112 using namespace digidoc;
113 
114 #ifdef _WIN32
115 #ifndef DIGIDOCPP_PATH_REGISTRY_KEY
116 #define DIGIDOCPP_PATH_REGISTRY_KEY "SOFTWARE\\Estonian ID Card\\digidocpp"
117 #endif
118 #endif
119 
123 std::string XmlConfPrivate::DEFAULT_CONF_LOC = "";
124 std::string XmlConfPrivate::USER_CONF_LOC = "";
125 
126 const std::string XmlConfPrivate::LOG_LEVEL = "log.level";
127 const std::string XmlConfPrivate::LOG_FILE = "log.file";
128 const std::string XmlConfPrivate::DIGEST_URI = "digest.uri";
129 const std::string XmlConfPrivate::SIGNATURE_URI = "signature.uri";
130 const std::string XmlConfPrivate::PKCS11_DRIVER_PATH = "pkcs11.driver.path";
131 const std::string XmlConfPrivate::CERT_STORE_PATH = "cert.store.path";
132 const std::string XmlConfPrivate::MANIFEST_XSD_PATH = "manifest.xsd.path";
133 const std::string XmlConfPrivate::XADES_XSD_PATH = "xades.xsd.path";
134 const std::string XmlConfPrivate::DSIG_XSD_PATH = "dsig.xsd.path";
135 const std::string XmlConfPrivate::PROXY_HOST = "proxy.host";
136 const std::string XmlConfPrivate::PROXY_PORT = "proxy.port";
137 const std::string XmlConfPrivate::PROXY_USER = "proxy.user";
138 const std::string XmlConfPrivate::PROXY_PASS = "proxy.pass";
139 const std::string XmlConfPrivate::PKCS12_CERT = "pkcs12.cert";
140 const std::string XmlConfPrivate::PKCS12_PASS = "pkcs12.pass";
141 const std::string XmlConfPrivate::PKCS12_DISABLE = "pkcs12.disable";
142 
144  : logLevel(Log::InfoType)
145  , pkcs12Disable(false)
146 {
147  // User conf path
148 #ifdef _WIN32
149  USER_CONF_LOC = util::File::env("APPDATA");
150  if (!USER_CONF_LOC.empty())
151  USER_CONF_LOC += "\\digidocpp\\digidocpp.conf";
152 #else
153  USER_CONF_LOC = util::File::env("HOME");
154  if (!USER_CONF_LOC.empty())
155  USER_CONF_LOC += "/.digidocpp/digidocpp.conf";
156 #endif
157 
158  // Global conf
159  DEFAULT_CONF_LOC.clear();
160  std::string overrideConf = util::File::env( "DIGIDOCPP_OVERRIDE_CONF" );
161  if (!overrideConf.empty()) //if there is environment variable defined, use this conf instead of others
162  {
163  DEFAULT_CONF_LOC = overrideConf;
164  return;
165  }
166 
167 #ifdef _WIN32
168  HKEY hkey;
169  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(DIGIDOCPP_PATH_REGISTRY_KEY), 0, KEY_QUERY_VALUE, &hkey)==ERROR_SUCCESS)
170  {
171  DWORD dwSize = MAX_PATH * sizeof(TCHAR);
172  TCHAR tcConfPath[MAX_PATH];
173  DWORD dwRet = RegQueryValueEx(hkey, TEXT("ConfigFile"), NULL, NULL, (LPBYTE)tcConfPath, &dwSize);
174  RegCloseKey(hkey);
175  if (dwRet == ERROR_SUCCESS)
177  else
178  DEBUG("Failed to open registry key \"%s\" ConfigFile value ", DIGIDOCPP_PATH_REGISTRY_KEY);
179  }
180 #elif defined(FRAMEWORK)
181  CFStringRef identifier = CFStringCreateWithCString(0, "ee.ria.digidocpp", kCFStringEncodingUTF8);
182  if(CFBundleRef bundle = CFBundleGetBundleWithIdentifier(identifier))
183  {
184  if(CFURLRef url = CFBundleCopyResourcesDirectoryURL(bundle))
185  {
186  char path[PATH_MAX];
187  if(CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)path, PATH_MAX))
188  {
189  DEFAULT_CONF_LOC = path;
190  DEFAULT_CONF_LOC += "/";
191  }
192  CFRelease(url);
193  }
194  CFRelease(bundle);
195  }
196  CFRelease(identifier);
197  DEFAULT_CONF_LOC += "digidocpp.conf";
198 #else
199  DEFAULT_CONF_LOC = DIGIDOCPP_CONFIG_DIR "/digidocpp.conf";
200 #endif
201 }
202 
208 std::auto_ptr<Configuration> XmlConfPrivate::read(const std::string &path) throw(IOException)
209 {
210  try
211  {
212  xml_schema::Properties props;
213  props.no_namespace_schema_location(
214  util::File::path(XmlConf::getDefaultConfDir(), "schema/conf.xsd"));
215  return configuration(path, xml_schema::Flags::dont_initialize, props);
216  }
217  catch(const xml_schema::Exception& e)
218  {
219  std::ostringstream oss;
220  oss << e;
221  THROW_IOEXCEPTION("Failed to parse configuration: %s - %s", path.c_str(), oss.str().c_str());
222  }
223  return std::auto_ptr<Configuration>(new Configuration);
224 }
225 
230 {
231  if(!Conf::isInitialized())
232  Conf::init(new XmlConf());
233 }
234 
235 
241 : d(new XmlConfPrivate)
242 {
243  try
244  {
246  }
247  catch(const IOException &e)
248  {
249  WARN("Failed to read global configuration '%s' file", e.getMsg().c_str());
250  }
251 
252  try
253  {
256  }
257  catch(const IOException &e)
258  {
259  WARN("Failed to read user home configuration '%s' file", e.getMsg().c_str());
260  }
261 }
262 
268 XmlConf::XmlConf(const std::string& path) throw(IOException)
269 : d(new XmlConfPrivate)
270 {
271  d->init(path, true);
272 }
273 
275 {
276  delete d;
277 }
278 
284 {
285  // the file path in conf is relative to the conf file's location
286  if( !XmlConfPrivate::DEFAULT_CONF_LOC.empty() )
288  return util::File::cwd();
289 }
290 
295 void XmlConfPrivate::init(const std::string& path, bool global) throw(IOException)
296 {
297  DEBUG("digidoc::XmlConf::init(%s)", path.c_str());
298  std::auto_ptr<Configuration> conf = read(path);
299  try
300  {
301  Configuration::ParamSequence paramSeq = conf->param();
302  for( Configuration::ParamSequence::const_iterator it = paramSeq.begin(); it != paramSeq.end(); it++)
303  {
304  if(LOG_LEVEL.compare(it->name()) == 0)
305  logLevel.setValue(atoi(std::string(*it).c_str()), it->lock(), global);
306  else if(LOG_FILE.compare(it->name()) == 0)
307  logFile.setValue(*it, it->lock(), global);
308  else if(DIGEST_URI.compare(it->name()) == 0)
309  digestUri.setValue(*it, it->lock(), global);
310  else if(SIGNATURE_URI.compare(it->name()) == 0)
311  signatureUri.setValue(*it, it->lock(), global);
312  else if(MANIFEST_XSD_PATH.compare(it->name()) == 0)
313  manifestXsdPath.setValue(*it, it->lock(), global);
314  else if(XADES_XSD_PATH.compare(it->name()) == 0)
315  xadesXsdPath.setValue(*it, it->lock(), global);
316  else if(DSIG_XSD_PATH.compare(it->name()) == 0)
317  dsigXsdPath.setValue(*it, it->lock(), global);
318  else if(PKCS11_DRIVER_PATH.compare(it->name()) == 0)
319  pkcs11DriverPath.setValue(*it, it->lock(), global);
320  else if(CERT_STORE_PATH.compare(it->name()) == 0)
321  certStorePath.setValue(*it, it->lock(), global);
322  else if(PROXY_HOST.compare(it->name()) == 0)
323  proxyHost.setValue(*it, it->lock(), global);
324  else if(PROXY_PORT.compare(it->name()) == 0)
325  proxyPort.setValue(*it, it->lock(), global);
326  else if(PROXY_USER.compare(it->name()) == 0)
327  proxyUser.setValue(*it, it->lock(), global);
328  else if(PROXY_PASS.compare(it->name()) == 0)
329  proxyPass.setValue(*it, it->lock(), global);
330  else if(PKCS12_CERT.compare(it->name()) == 0)
331  pkcs12Cert.setValue(*it, it->lock(), global);
332  else if(PKCS12_PASS.compare(it->name()) == 0)
333  pkcs12Pass.setValue(*it, it->lock(), global);
334  else if(PKCS12_DISABLE.compare(it->name()) == 0)
335  pkcs12Disable.setValue((*it).compare("true") == 0, it->lock(), global);
336  else
337  WARN("Unknown configuration parameter %s", it->name().c_str());
338  }
339 
340  Configuration::OcspSequence ocspSeq = conf->ocsp();
341  for( Configuration::OcspSequence::const_iterator it = ocspSeq.begin(); it != ocspSeq.end(); ++it)
342  {
343  Conf::OCSPConf o;
344  o.issuer = it->issuer();
345  o.url = it->url();
346  o.cert = it->cert();
347  ocsp.push_back(o);
348  }
349  }
350  catch(const xml_schema::Exception& e)
351  {
352  std::ostringstream oss;
353  oss << e;
354  THROW_IOEXCEPTION("Failed to parse configuration: %s", oss.str().c_str());
355  }
356 }
357 
363 {
364  return d->logLevel.value;
365 }
366 
371 std::string XmlConf::getLogFile() const
372 {
373  return d->logFile.value.empty() ? Conf::getLogFile() : d->logFile.value;
374 }
375 
387 std::string XmlConf::getDigestUri() const
388 {
389  return d->digestUri.value.empty() ? Conf::getDigestUri() : d->digestUri.value;
390 }
391 
403 std::string XmlConf::getSignatureUri() const
404 {
406 }
407 
408 
414 {
416 }
417 
422 std::string XmlConf::getManifestXsdPath() const
423 {
426 }
427 
432 std::string XmlConf::getXadesXsdPath() const
433 {
436 }
437 
442 std::string XmlConf::getDsigXsdPath() const
443 {
446 }
447 
452 std::string XmlConf::getPKCS11DriverPath() const
453 {
455 }
456 
462 Conf::OCSPConf XmlConf::getOCSP(const std::string &issuer) const
463 {
464  for(std::vector<OCSPConf>::const_iterator i = d->ocsp.begin(); i != d->ocsp.end(); ++i)
465  {
466  if(i->issuer == issuer)
467  return *i;
468  }
469  return Conf::getOCSP(issuer);
470 }
471 
476 std::string XmlConf::getCertStorePath() const
477 {
478 #ifdef FRAMEWORK
479  return getDefaultConfDir() + "/certs";
480 #else
481  std::string path = d->certStorePath.value.empty() ? Conf::getCertStorePath() : d->certStorePath.value;
482  if( path.empty() ) return path;
483  return util::File::isRelative( path ) ? util::File::path( getDefaultConfDir(), path ) : path;
484 #endif
485 }
486 
491 std::string XmlConf::getProxyHost() const
492 {
493  return d->proxyHost.value.empty() ? Conf::getProxyHost() : d->proxyHost.value;
494 }
495 
500 std::string XmlConf::getProxyPort() const
501 {
502  return d->proxyPort.value.empty() ? Conf::getProxyPort() : d->proxyPort.value;
503 }
504 
509 std::string XmlConf::getProxyUser() const
510 {
511  return d->proxyUser.value.empty() ? Conf::getProxyUser() : d->proxyUser.value;
512 }
513 
518 std::string XmlConf::getProxyPass() const
519 {
520  return d->proxyPass.value.empty() ? Conf::getProxyPass() : d->proxyPass.value;
521 }
522 
527 std::string XmlConf::getPKCS12Cert() const
528 {
529  return d->pkcs12Cert.value.empty() ? Conf::getPKCS12Cert() : d->pkcs12Cert.value;
530 }
531 
536 std::string XmlConf::getPKCS12Pass() const
537 {
538  return d->pkcs12Pass.value.empty() ? Conf::getPKCS12Pass() : d->pkcs12Pass.value;
539 }
540 
546 {
547  return d->pkcs12Disable.value;
548 }
549 
556 void XmlConf::setProxyHost( const std::string &host ) throw(IOException)
557 {
558  if( d->proxyHost.locked )
559  return;
560  d->proxyHost = host;
561  d->setUserConf(XmlConfPrivate::PROXY_HOST, host);
562 }
563 
570 void XmlConf::setProxyPort( const std::string &port ) throw(IOException)
571 {
572  if( d->proxyPort.locked )
573  return;
574  d->proxyPort = port;
575  d->setUserConf(XmlConfPrivate::PROXY_PORT, port);
576 }
577 
584 void XmlConf::setProxyUser( const std::string &user ) throw(IOException)
585 {
586  if( d->proxyUser.locked )
587  return;
588  d->proxyUser = user;
589  d->setUserConf(XmlConfPrivate::PROXY_USER, user);
590 }
591 
598 void XmlConf::setProxyPass( const std::string &pass ) throw(IOException)
599 {
600  if( d->proxyPass.locked )
601  return;
602  d->proxyPass = pass;
603  d->setUserConf(XmlConfPrivate::PROXY_PASS, pass);
604 }
605 
613 void XmlConf::setPKCS12Cert( const std::string &cert ) throw(IOException)
614 {
615  if( d->pkcs12Cert.locked )
616  return;
617  d->pkcs12Cert = cert;
618  d->setUserConf(XmlConfPrivate::PKCS12_CERT, cert);
619 }
620 
627 void XmlConf::setPKCS12Pass( const std::string &pass ) throw(IOException)
628 {
629  if( d->pkcs12Pass.locked )
630  return;
631  d->pkcs12Pass = pass;
632  d->setUserConf(XmlConfPrivate::PKCS12_PASS, pass);
633 }
634 
641 void XmlConf::setPKCS12Disable( bool disable ) throw(IOException)
642 {
643  if( d->pkcs12Disable.locked )
644  return;
645  d->pkcs12Disable = disable;
646  d->setUserConf(XmlConfPrivate::PKCS12_DISABLE, disable ? "true" : "false");
647 }
648 
657 void XmlConf::setOCSP(const std::string &issuer, const std::string &url, const std::string &cert) throw(IOException)
658 {
659  std::auto_ptr<Configuration> conf(new Configuration);
661  conf = d->read(XmlConfPrivate::USER_CONF_LOC);
662  try
663  {
664  Configuration::OcspSequence ocspSeq = conf->ocsp();
665  for(Configuration::OcspSequence::iterator it = ocspSeq.begin(); it != ocspSeq.end(); it++)
666  {
667  if (issuer.compare(it->issuer()) == 0)
668  {
669  ocspSeq.erase(it);
670  break;
671  }
672  }
673  if(url.size() || cert.size()) //if it's a new parameter
674  ocspSeq.push_back(Ocsp(url, cert, issuer));
675  conf->ocsp(ocspSeq); //replace all ocsp data with new modified ocsp sequence
676  }
677  catch(const xml_schema::Exception& e)
678  {
679  std::ostringstream oss;
680  oss << e;
681  THROW_IOEXCEPTION("(in set OCSP) Failed to parse configuration: %s", oss.str().c_str());
682  }
683  d->serializeUserConf(*conf);
684 }
685 
693 void XmlConfPrivate::setUserConf(const std::string &paramName, const std::string &value) throw(IOException)
694 {
695  std::auto_ptr<Configuration> conf(new Configuration);
696  if(util::File::fileExists(USER_CONF_LOC))
697  conf = read(USER_CONF_LOC);
698  try
699  {
700  Configuration::ParamSequence paramSeq = conf->param();
701  for(Configuration::ParamSequence::iterator it = paramSeq.begin(); it != paramSeq.end(); it++)
702  {
703  if(paramName.compare(it->name()) == 0)
704  {
705  paramSeq.erase(it);
706  break;
707  }
708  }
709  if(value.size()) //if it's a new parameter
710  paramSeq.push_back(Param(value, paramName));
711  conf->param(paramSeq); //replace all param data with new modified param sequence
712  }
713  catch (const xml_schema::Exception& e)
714  {
715  std::ostringstream oss;
716  oss << e;
717  THROW_IOEXCEPTION("(in set %s) Failed to parse configuration: %s", paramName.c_str(), oss.str().c_str());
718  }
719  serializeUserConf(*conf);
720 }
721 
728 void XmlConfPrivate::serializeUserConf(const Configuration &pConf) throw(IOException)
729 {
732  f_string enc = util::File::encodeName(USER_CONF_LOC);
733  std::ofstream ofs(enc.c_str());
734  if (ofs.fail())
735  THROW_IOEXCEPTION("Failed to open configuration: %s", USER_CONF_LOC.c_str());
736  xml_schema::NamespaceInfomap map;
737  map[""].name = "";
738  map[""].schema = util::File::path(XmlConf::getDefaultConfDir(), "schema/conf.xsd");
739  configuration(ofs, pConf, map);
740 }