LCOV - code coverage report
Current view: top level - xmlsecurity/source/xmlsec/nss - nssinitializer.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 113 182 62.1 %
Date: 2014-04-11 Functions: 12 20 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : /*
      22             :  * and turn off the additional virtual methods which are part of some interfaces when compiled
      23             :  * with debug
      24             :  */
      25             : #ifdef DEBUG
      26             : #undef DEBUG
      27             : #endif
      28             : 
      29             : 
      30             : #include <com/sun/star/mozilla/XMozillaBootstrap.hpp>
      31             : #include <com/sun/star/xml/crypto/DigestID.hpp>
      32             : #include <com/sun/star/xml/crypto/CipherID.hpp>
      33             : #include <cppuhelper/supportsservice.hxx>
      34             : 
      35             : #include <officecfg/Office/Common.hxx>
      36             : 
      37             : #include <sal/types.h>
      38             : #include <rtl/instance.hxx>
      39             : #include <rtl/bootstrap.hxx>
      40             : #include <rtl/string.hxx>
      41             : #include <rtl/strbuf.hxx>
      42             : #include <osl/file.hxx>
      43             : #include <osl/thread.h>
      44             : #include <sal/log.hxx>
      45             : 
      46             : #include "seinitializer_nssimpl.hxx"
      47             : #include "../diagnose.hxx"
      48             : 
      49             : #include "securityenvironment_nssimpl.hxx"
      50             : #include "digestcontext.hxx"
      51             : #include "ciphercontext.hxx"
      52             : 
      53             : #include <boost/scoped_array.hpp>
      54             : 
      55             : #include <nspr.h>
      56             : #include <cert.h>
      57             : #include <nss.h>
      58             : #include <pk11pub.h>
      59             : #include <secmod.h>
      60             : #include <nssckbi.h>
      61             : 
      62             : namespace cssu = css::uno;
      63             : namespace cssl = css::lang;
      64             : 
      65             : using namespace xmlsecurity;
      66             : using namespace com::sun::star;
      67             : 
      68             : #define IMPLEMENTATION_NAME "com.sun.star.xml.security.bridge.xmlsec.NSSInitializer_NssImpl"
      69             : 
      70             : #define ROOT_CERTS "Root Certs for OpenOffice.org"
      71             : 
      72             : extern "C" void nsscrypto_finalize();
      73             : 
      74             : 
      75             : namespace
      76             : {
      77             : 
      78             : bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool & out_nss_init );
      79             : 
      80          62 : struct InitNSSInitialize
      81             : {
      82             :     css::uno::Reference< css::uno::XComponentContext > m_xContext;
      83             : 
      84          62 :     InitNSSInitialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext )
      85          62 :     : m_xContext( rxContext )
      86             :     {
      87          62 :     }
      88             : 
      89           2 :     bool * operator()()
      90             :         {
      91             :             static bool bInitialized = false;
      92           2 :             bool bNSSInit = false;
      93           2 :             bInitialized = nsscrypto_initialize( m_xContext, bNSSInit );
      94           2 :             if (bNSSInit)
      95           2 :                 atexit(nsscrypto_finalize );
      96           2 :              return & bInitialized;
      97             :         }
      98             : };
      99             : 
     100             : struct GetNSSInitStaticMutex
     101             : {
     102           2 :     ::osl::Mutex* operator()()
     103             :     {
     104           2 :         static ::osl::Mutex aNSSInitMutex;
     105           2 :         return &aNSSInitMutex;
     106             :     }
     107             : };
     108             : 
     109           2 : void deleteRootsModule()
     110             : {
     111           2 :     SECMODModule *RootsModule = 0;
     112           2 :     SECMODModuleList *list = SECMOD_GetDefaultModuleList();
     113           2 :     SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
     114           2 :     SECMOD_GetReadLock(lock);
     115             : 
     116           6 :     while (!RootsModule && list)
     117             :     {
     118           2 :         SECMODModule *module = list->module;
     119             : 
     120           6 :         for (int i=0; i < module->slotCount; i++)
     121             :         {
     122           4 :             PK11SlotInfo *slot = module->slots[i];
     123           4 :             if (PK11_IsPresent(slot))
     124             :             {
     125           4 :                 if (PK11_HasRootCerts(slot))
     126             :                 {
     127             :                     xmlsec_trace("The root certifificates module \"%s"
     128             :                               "\" is already loaded: \n%s",
     129           0 :                               module->commonName,  module->dllName);
     130             : 
     131           0 :                     RootsModule = SECMOD_ReferenceModule(module);
     132           0 :                     break;
     133             :                 }
     134             :             }
     135             :         }
     136           2 :         list = list->next;
     137             :     }
     138           2 :     SECMOD_ReleaseReadLock(lock);
     139             : 
     140           2 :     if (RootsModule)
     141             :     {
     142             :         PRInt32 modType;
     143           0 :         if (SECSuccess == SECMOD_DeleteModule(RootsModule->commonName, &modType))
     144             :         {
     145           0 :             xmlsec_trace("Deleted module \"%s\".", RootsModule->commonName);
     146             :         }
     147             :         else
     148             :         {
     149             :             xmlsec_trace("Failed to delete \"%s\" : \n%s",
     150           0 :                       RootsModule->commonName, RootsModule->dllName);
     151             :         }
     152           0 :         SECMOD_DestroyModule(RootsModule);
     153           0 :         RootsModule = 0;
     154             :     }
     155           2 : }
     156             : 
     157           2 : OString getMozillaCurrentProfile( const css::uno::Reference< css::uno::XComponentContext > &rxContext )
     158             : {
     159             :     // first, try to get the profile from "MOZILLA_CERTIFICATE_FOLDER"
     160           2 :     const char* pEnv = getenv("MOZILLA_CERTIFICATE_FOLDER");
     161           2 :     if (pEnv)
     162             :     {
     163             :         SAL_INFO(
     164             :             "xmlsecurity.xmlsec",
     165             :             "Using Mozilla profile from MOZILLA_CERTIFICATE_FOLDER=" << pEnv);
     166           0 :         return OString(pEnv);
     167             :     }
     168             : 
     169             :     // second, try to get saved user-preference
     170             :     try
     171             :     {
     172             :         OUString sUserSetCertPath =
     173           2 :             officecfg::Office::Common::Security::Scripting::CertDir::get().get_value_or(OUString());
     174             : 
     175           2 :         if (!sUserSetCertPath.isEmpty())
     176             :         {
     177             :             SAL_INFO(
     178             :                 "xmlsecurity.xmlsec",
     179             :                 "Using Mozilla profile from /org.openoffice.Office.Common/"
     180             :                     "Security/Scripting/CertDir: " << sUserSetCertPath);
     181           0 :             return OUStringToOString(sUserSetCertPath, osl_getThreadTextEncoding());
     182           2 :         }
     183             :     }
     184           0 :     catch (const uno::Exception &e)
     185             :     {
     186             :         SAL_WARN(
     187             :             "xmlsecurity.xmlsec",
     188             :             "getMozillaCurrentProfile: caught exception " << e.Message);
     189             :     }
     190             : 
     191             :     // third, dig around to see if there's one available
     192             :     mozilla::MozillaProductType productTypes[3] = {
     193             :         mozilla::MozillaProductType_Thunderbird,
     194             :         mozilla::MozillaProductType_Firefox,
     195           2 :         mozilla::MozillaProductType_Mozilla };
     196           2 :     int nProduct = SAL_N_ELEMENTS(productTypes);
     197             : 
     198           2 :     uno::Reference<uno::XInterface> xInstance = rxContext->getServiceManager()->createInstanceWithContext("com.sun.star.mozilla.MozillaBootstrap", rxContext);
     199             :     OSL_ENSURE( xInstance.is(), "failed to create instance" );
     200             : 
     201             :     uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap
     202           4 :         =  uno::Reference<mozilla::XMozillaBootstrap>(xInstance,uno::UNO_QUERY);
     203             :     OSL_ENSURE( xMozillaBootstrap.is(), "failed to create instance" );
     204             : 
     205           2 :     if (xMozillaBootstrap.is())
     206             :     {
     207           0 :         for (int i=0; i<nProduct; ++i)
     208             :         {
     209           0 :             OUString profile = xMozillaBootstrap->getDefaultProfile(productTypes[i]);
     210             : 
     211           0 :             if (!profile.isEmpty())
     212             :             {
     213           0 :                 OUString sProfilePath = xMozillaBootstrap->getProfilePath( productTypes[i], profile );
     214             :                 SAL_INFO(
     215             :                     "xmlsecurity.xmlsec",
     216             :                     "Using Mozilla profile " << sProfilePath);
     217           0 :                 return OUStringToOString(sProfilePath, osl_getThreadTextEncoding());
     218             :             }
     219           0 :         }
     220             :     }
     221             : 
     222             :     SAL_INFO("xmlsecurity.xmlsec", "No Mozilla profile found");
     223           4 :     return OString();
     224             : }
     225             : 
     226             : //Older versions of Firefox (FF), for example FF2, and Thunderbird (TB) 2 write
     227             : //the roots certificate module (libnssckbi.so), which they use, into the
     228             : //profile. This module will then already be loaded during NSS_Init (and the
     229             : //other init functions). This fails in two cases. First, FF3 was used to create
     230             : //the profile, or possibly used that profile before, and second the profile was
     231             : //used on a different platform.
     232             : //
     233             : //Then one needs to add the roots module oneself. This should be done with
     234             : //SECMOD_LoadUserModule rather then SECMOD_AddNewModule. The latter would write
     235             : //the location of the roots module to the profile, which makes FF2 and TB2 use
     236             : //it instead of there own module.
     237             : //
     238             : //When using SYSTEM_NSS then the libnss3.so lib is typically found in /usr/lib.
     239             : //This folder may, however, NOT contain the roots certificate module. That is,
     240             : //just providing the library name in SECMOD_LoadUserModule or
     241             : //SECMOD_AddNewModule will FAIL to load the mozilla unless the LD_LIBRARY_PATH
     242             : //contains an FF or TB installation.
     243             : //ATTENTION: DO NOT call this function directly instead use initNSS
     244             : //return true - whole initialization was successful
     245             : //param out_nss_init = true: at least the NSS initialization (NSS_InitReadWrite
     246             : //was successful and therefor NSS_Shutdown should be called when terminating.
     247           2 : bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool & out_nss_init )
     248             : {
     249           2 :     bool return_value = true;
     250             : 
     251             :     // this method must be called only once, no need for additional lock
     252           2 :     OString sCertDir;
     253             : 
     254             : #ifdef XMLSEC_CRYPTO_NSS
     255           2 :     sCertDir = getMozillaCurrentProfile(rxContext);
     256             : #else
     257             :     (void) rxContext;
     258             : #endif
     259           2 :     xmlsec_trace( "Using profile: %s", sCertDir.getStr() );
     260             : 
     261           2 :     PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
     262             : 
     263           2 :     bool bSuccess = true;
     264             :     // there might be no profile
     265           2 :     if ( !sCertDir.isEmpty() )
     266             :     {
     267           0 :         if( NSS_InitReadWrite( sCertDir.getStr() ) != SECSuccess )
     268             :         {
     269           0 :             xmlsec_trace("Initializing NSS with profile failed.");
     270           0 :             int errlen = PR_GetErrorTextLength();
     271           0 :             if(errlen > 0)
     272             :             {
     273           0 :                 boost::scoped_array<char> const error(new char[errlen + 1]);
     274           0 :                 PR_GetErrorText(error.get());
     275           0 :                 xmlsec_trace("%s", error.get());
     276             :             }
     277           0 :             bSuccess = false;
     278             :         }
     279             :     }
     280             : 
     281           2 :     if( sCertDir.isEmpty() || !bSuccess )
     282             :     {
     283           2 :         xmlsec_trace("Initializing NSS without profile.");
     284           2 :         if ( NSS_NoDB_Init(NULL) != SECSuccess )
     285             :         {
     286           0 :             xmlsec_trace("Initializing NSS without profile failed.");
     287           0 :             int errlen = PR_GetErrorTextLength();
     288           0 :             if(errlen > 0)
     289             :             {
     290           0 :                 boost::scoped_array<char> const error(new char[errlen + 1]);
     291           0 :                 PR_GetErrorText(error.get());
     292           0 :                 xmlsec_trace("%s", error.get());
     293             :             }
     294           0 :             return false ;
     295             :         }
     296             :     }
     297           2 :     out_nss_init = true;
     298             : 
     299             : #ifdef XMLSEC_CRYPTO_NSS
     300             : #if defined SYSTEM_NSS
     301           2 :     if (!SECMOD_HasRootCerts())
     302             : #endif
     303             :     {
     304           2 :         deleteRootsModule();
     305             : 
     306             : #if defined SYSTEM_NSS
     307           2 :         OUString rootModule("libnssckbi" SAL_DLLEXTENSION);
     308             : #else
     309             :         OUString rootModule("${LO_LIB_DIR}/libnssckbi" SAL_DLLEXTENSION);
     310             : #endif
     311           2 :         ::rtl::Bootstrap::expandMacros(rootModule);
     312             : 
     313           4 :         OUString rootModulePath;
     314           2 :         if (::osl::File::E_None == ::osl::File::getSystemPathFromFileURL(rootModule, rootModulePath))
     315             :         {
     316           2 :             OString ospath = OUStringToOString(rootModulePath, osl_getThreadTextEncoding());
     317           4 :             OString aStr = "name=\"" ROOT_CERTS "\" library=\"" + ospath + "\"";
     318             : 
     319             :             SECMODModule * RootsModule =
     320             :                 SECMOD_LoadUserModule(
     321           2 :                     const_cast<char*>(aStr.getStr()),
     322             :                     0, // no parent
     323           2 :                     PR_FALSE); // do not recurse
     324             : 
     325           2 :             if (RootsModule)
     326             :             {
     327             : 
     328           2 :                 bool found = RootsModule->loaded;
     329             : 
     330           2 :                 SECMOD_DestroyModule(RootsModule);
     331           2 :                 RootsModule = 0;
     332           2 :                 if (found)
     333             :                     xmlsec_trace("Added new root certificate module "
     334           2 :                               "\"" ROOT_CERTS "\" contained in \n%s", ospath.getStr());
     335             :                 else
     336             :                 {
     337             :                     xmlsec_trace("FAILED to load the new root certificate module "
     338           0 :                               "\"" ROOT_CERTS "\" contained in \n%s", ospath.getStr());
     339           0 :                     return_value = false;
     340             :                 }
     341             :             }
     342             :             else
     343             :             {
     344             :                 xmlsec_trace("FAILED to add new root certifice module: "
     345           0 :                           "\"" ROOT_CERTS "\" contained in \n%s", ospath.getStr());
     346           0 :                 return_value = false;
     347             : 
     348           2 :             }
     349             :         }
     350             :         else
     351             :         {
     352           0 :             xmlsec_trace("Adding new root certificate module failed.");
     353           0 :             return_value = false;
     354           2 :         }
     355             :     }
     356             : #endif
     357             : 
     358           2 :     return return_value;
     359             : }
     360             : 
     361             : 
     362             : // must be extern "C" because we pass the function pointer to atexit
     363           2 : extern "C" void nsscrypto_finalize()
     364             : {
     365           2 :     SECMODModule *RootsModule = SECMOD_FindModule(ROOT_CERTS);
     366             : 
     367           2 :     if (RootsModule)
     368             :     {
     369             : 
     370           2 :         if (SECSuccess == SECMOD_UnloadUserModule(RootsModule))
     371             :         {
     372           2 :             xmlsec_trace("Unloaded module \"" ROOT_CERTS "\".");
     373             :         }
     374             :         else
     375             :         {
     376           0 :             xmlsec_trace("Failed unloading module \"" ROOT_CERTS "\".");
     377             :         }
     378           2 :         SECMOD_DestroyModule(RootsModule);
     379             :     }
     380             :     else
     381             :     {
     382             :         xmlsec_trace("Unloading module \"" ROOT_CERTS
     383           0 :                   "\" failed because it was not found.");
     384             :     }
     385           2 :     PK11_LogoutAll();
     386           2 :     NSS_Shutdown();
     387           2 : }
     388             : } // namespace
     389             : 
     390           0 : ONSSInitializer::ONSSInitializer(
     391             :     const css::uno::Reference< css::uno::XComponentContext > &rxContext)
     392           0 :     :m_xContext( rxContext )
     393             : {
     394           0 : }
     395             : 
     396          64 : ONSSInitializer::~ONSSInitializer()
     397             : {
     398          64 : }
     399             : 
     400          62 : bool ONSSInitializer::initNSS( const css::uno::Reference< css::uno::XComponentContext > &rxContext )
     401             : {
     402             :     return *rtl_Instance< bool, InitNSSInitialize, ::osl::MutexGuard, GetNSSInitStaticMutex >
     403          62 :                 ::create( InitNSSInitialize( rxContext ), GetNSSInitStaticMutex() );
     404             : }
     405             : 
     406          27 : css::uno::Reference< css::xml::crypto::XDigestContext > SAL_CALL ONSSInitializer::getDigestContext( ::sal_Int32 nDigestID, const css::uno::Sequence< css::beans::NamedValue >& aParams )
     407             :     throw (css::lang::IllegalArgumentException, css::uno::RuntimeException, std::exception)
     408             : {
     409          27 :     SECOidTag nNSSDigestID = SEC_OID_UNKNOWN;
     410          27 :     sal_Int32 nDigestLength = 0;
     411          27 :     bool b1KData = false;
     412          27 :     if ( nDigestID == css::xml::crypto::DigestID::SHA256
     413          22 :       || nDigestID == css::xml::crypto::DigestID::SHA256_1K )
     414             :     {
     415          27 :         nNSSDigestID = SEC_OID_SHA256;
     416          27 :         nDigestLength = 32;
     417          27 :         b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA256_1K );
     418             :     }
     419           0 :     else if ( nDigestID == css::xml::crypto::DigestID::SHA1
     420           0 :            || nDigestID == css::xml::crypto::DigestID::SHA1_1K )
     421             :     {
     422           0 :         nNSSDigestID = SEC_OID_SHA1;
     423           0 :         nDigestLength = 20;
     424           0 :         b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA1_1K );
     425             :     }
     426             :     else
     427           0 :         throw css::lang::IllegalArgumentException("Unexpected digest requested.", css::uno::Reference< css::uno::XInterface >(), 1 );
     428             : 
     429          27 :     if ( aParams.getLength() )
     430           0 :         throw css::lang::IllegalArgumentException("Unexpected arguments provided for digest creation.", css::uno::Reference< css::uno::XInterface >(), 2 );
     431             : 
     432          27 :     css::uno::Reference< css::xml::crypto::XDigestContext > xResult;
     433          27 :     if( initNSS( m_xContext ) )
     434             :     {
     435          27 :         PK11Context* pContext = PK11_CreateDigestContext( nNSSDigestID );
     436          27 :         if ( pContext && PK11_DigestBegin( pContext ) == SECSuccess )
     437          27 :             xResult = new ODigestContext( pContext, nDigestLength, b1KData );
     438             :     }
     439             : 
     440          27 :     return xResult;
     441             : }
     442             : 
     443          35 : css::uno::Reference< css::xml::crypto::XCipherContext > SAL_CALL ONSSInitializer::getCipherContext( ::sal_Int32 nCipherID, const css::uno::Sequence< ::sal_Int8 >& aKey, const css::uno::Sequence< ::sal_Int8 >& aInitializationVector, sal_Bool bEncryption, const css::uno::Sequence< css::beans::NamedValue >& aParams )
     444             :     throw (css::lang::IllegalArgumentException, css::uno::RuntimeException, std::exception)
     445             : {
     446          35 :     CK_MECHANISM_TYPE nNSSCipherID = 0;
     447          35 :     bool bW3CPadding = false;
     448          35 :     if ( nCipherID == css::xml::crypto::CipherID::AES_CBC_W3C_PADDING )
     449             :     {
     450          35 :         nNSSCipherID = CKM_AES_CBC;
     451          35 :         bW3CPadding = true;
     452             : 
     453          35 :         if ( aKey.getLength() != 16 && aKey.getLength() != 24 && aKey.getLength() != 32 )
     454           0 :             throw css::lang::IllegalArgumentException("Unexpected key length.", css::uno::Reference< css::uno::XInterface >(), 2 );
     455             : 
     456          35 :         if ( aParams.getLength() )
     457           0 :             throw css::lang::IllegalArgumentException("Unexpected arguments provided for cipher creation.", css::uno::Reference< css::uno::XInterface >(), 5 );
     458             :     }
     459             :     else
     460           0 :         throw css::lang::IllegalArgumentException("Unexpected cipher requested.", css::uno::Reference< css::uno::XInterface >(), 1 );
     461             : 
     462          35 :     css::uno::Reference< css::xml::crypto::XCipherContext > xResult;
     463          35 :     if( initNSS( m_xContext ) )
     464             :     {
     465          35 :         if ( aInitializationVector.getLength() != PK11_GetIVLength( nNSSCipherID ) )
     466           0 :             throw css::lang::IllegalArgumentException("Unexpected length of initialization vector.", css::uno::Reference< css::uno::XInterface >(), 3 );
     467             : 
     468          35 :         xResult = OCipherContext::Create( nNSSCipherID, aKey, aInitializationVector, bEncryption, bW3CPadding );
     469             :     }
     470             : 
     471          35 :     return xResult;
     472             : }
     473             : 
     474           0 : OUString ONSSInitializer_getImplementationName ()
     475             :     throw (cssu::RuntimeException)
     476             : {
     477             : 
     478           0 :     return OUString ( IMPLEMENTATION_NAME );
     479             : }
     480             : 
     481           0 : cssu::Sequence< OUString > SAL_CALL ONSSInitializer_getSupportedServiceNames(  )
     482             :     throw (cssu::RuntimeException)
     483             : {
     484           0 :     cssu::Sequence < OUString > aRet(1);
     485           0 :     OUString* pArray = aRet.getArray();
     486           0 :     pArray[0] =  OUString ( NSS_SERVICE_NAME );
     487           0 :     return aRet;
     488             : }
     489             : 
     490           0 : cssu::Reference< cssu::XInterface > SAL_CALL ONSSInitializer_createInstance( const cssu::Reference< cssl::XMultiServiceFactory > & rSMgr)
     491             :     throw( cssu::Exception )
     492             : {
     493           0 :     return (cppu::OWeakObject*) new ONSSInitializer( comphelper::getComponentContext(rSMgr) );
     494             : }
     495             : 
     496             : /* XServiceInfo */
     497           0 : OUString SAL_CALL ONSSInitializer::getImplementationName()
     498             :     throw (cssu::RuntimeException, std::exception)
     499             : {
     500           0 :     return ONSSInitializer_getImplementationName();
     501             : }
     502             : 
     503           0 : sal_Bool SAL_CALL ONSSInitializer::supportsService( const OUString& rServiceName )
     504             :     throw (cssu::RuntimeException, std::exception)
     505             : {
     506           0 :     return cppu::supportsService(this, rServiceName);
     507             : }
     508             : 
     509           0 : cssu::Sequence< OUString > SAL_CALL ONSSInitializer::getSupportedServiceNames(  )
     510             :     throw (cssu::RuntimeException, std::exception)
     511             : {
     512           0 :     return ONSSInitializer_getSupportedServiceNames();
     513             : }
     514             : 
     515             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10