LCOV - code coverage report
Current view: top level - libreoffice/sc/source/core/data - tabprotection.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 55 191 28.8 %
Date: 2012-12-27 Functions: 19 51 37.3 %
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             : #include "tabprotection.hxx"
      21             : #include "svl/PasswordHelper.hxx"
      22             : #include <comphelper/docpasswordhelper.hxx>
      23             : #include "document.hxx"
      24             : 
      25             : #include <vector>
      26             : 
      27             : #define DEBUG_TAB_PROTECTION 0
      28             : 
      29             : #define URI_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1"
      30             : #define URI_XLS_LEGACY "http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"
      31             : 
      32             : using namespace ::com::sun::star;
      33             : using ::com::sun::star::uno::Sequence;
      34             : using ::rtl::OUString;
      35             : using ::rtl::OUStringBuffer;
      36             : using ::std::vector;
      37             : 
      38             : // ============================================================================
      39             : 
      40           2 : bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash1, ScPasswordHash eHash2)
      41             : {
      42           2 :     if (rDoc.IsDocProtected())
      43             :     {
      44           0 :         const ScDocProtection* p = rDoc.GetDocProtection();
      45           0 :         if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
      46           0 :             return true;
      47             :     }
      48             : 
      49           2 :     SCTAB nTabCount = rDoc.GetTableCount();
      50           4 :     for (SCTAB i = 0; i < nTabCount; ++i)
      51             :     {
      52           2 :         const ScTableProtection* p = rDoc.GetTabProtection(i);
      53           2 :         if (!p || !p->isProtected())
      54             :             // Sheet not protected.  Skip it.
      55           2 :             continue;
      56             : 
      57           0 :         if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
      58           0 :             return true;
      59             :     }
      60             : 
      61           2 :     return false;
      62             : }
      63             : 
      64           0 : OUString ScPassHashHelper::getHashURI(ScPasswordHash eHash)
      65             : {
      66           0 :     switch (eHash)
      67             :     {
      68             :         case PASSHASH_SHA1:
      69           0 :             return OUString(RTL_CONSTASCII_USTRINGPARAM(URI_SHA1));
      70             :         case PASSHASH_XL:
      71           0 :             return OUString(RTL_CONSTASCII_USTRINGPARAM(URI_XLS_LEGACY));
      72             :         case PASSHASH_UNSPECIFIED:
      73             :         default:
      74             :             ;
      75             :     }
      76           0 :     return OUString();
      77             : }
      78             : 
      79           0 : ScPasswordHash ScPassHashHelper::getHashTypeFromURI(const OUString& rURI)
      80             : {
      81           0 :     if ( rURI == URI_SHA1 )
      82           0 :         return PASSHASH_SHA1;
      83           0 :     else if ( rURI == URI_XLS_LEGACY )
      84           0 :         return PASSHASH_XL;
      85           0 :     return PASSHASH_UNSPECIFIED;
      86             : }
      87             : 
      88             : // ============================================================================
      89             : 
      90          24 : ScPassHashProtectable::~ScPassHashProtectable()
      91             : {
      92          24 : }
      93             : 
      94             : // ============================================================================
      95             : 
      96          24 : class ScTableProtectionImpl
      97             : {
      98             : public:
      99             :     static Sequence<sal_Int8> hashPassword(const String& aPassText, ScPasswordHash eHash = PASSHASH_SHA1);
     100             :     static Sequence<sal_Int8> hashPassword(const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash = PASSHASH_SHA1);
     101             : 
     102             :     explicit ScTableProtectionImpl(SCSIZE nOptSize);
     103             :     explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
     104             : 
     105             :     bool isProtected() const;
     106             :     bool isProtectedWithPass() const;
     107             :     void setProtected(bool bProtected);
     108             : 
     109             :     bool isPasswordEmpty() const;
     110             :     bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
     111             :     void setPassword(const String& aPassText);
     112             :     ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(
     113             :         ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
     114             :     void setPasswordHash(
     115             :         const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
     116             :         ScPasswordHash eHash = PASSHASH_SHA1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED);
     117             :     bool verifyPassword(const String& aPassText) const;
     118             : 
     119             :     bool isOptionEnabled(SCSIZE nOptId) const;
     120             :     void setOption(SCSIZE nOptId, bool bEnabled);
     121             : 
     122             : private:
     123             :     String maPassText;
     124             :     ::com::sun::star::uno::Sequence<sal_Int8>   maPassHash;
     125             :     ::std::vector<bool> maOptions;
     126             :     bool mbEmptyPass;
     127             :     bool mbProtected;
     128             :     ScPasswordHash meHash1;
     129             :     ScPasswordHash meHash2;
     130             : };
     131             : 
     132           0 : Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const String& aPassText, ScPasswordHash eHash)
     133             : {
     134           0 :     Sequence<sal_Int8> aHash;
     135           0 :     switch (eHash)
     136             :     {
     137             :         case PASSHASH_XL:
     138           0 :             aHash = ::comphelper::DocPasswordHelper::GetXLHashAsSequence( aPassText, RTL_TEXTENCODING_UTF8 );
     139           0 :         break;
     140             :         case PASSHASH_SHA1:
     141           0 :             SvPasswordHelper::GetHashPassword(aHash, aPassText);
     142           0 :         break;
     143             :         default:
     144             :             ;
     145             :     }
     146           0 :     return aHash;
     147             : }
     148             : 
     149           0 : Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(
     150             :     const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash)
     151             : {
     152           0 :     if (!rPassHash.getLength() || eHash == PASSHASH_UNSPECIFIED)
     153           0 :         return rPassHash;
     154             : 
     155             :     // TODO: Right now, we only support double-hash by SHA1.
     156           0 :     if (eHash == PASSHASH_SHA1)
     157             :     {
     158           0 :         vector<sal_Char> aChars;
     159           0 :         sal_Int32 n = rPassHash.getLength();
     160           0 :         aChars.reserve(n);
     161           0 :         for (sal_Int32 i = 0; i < n; ++i)
     162           0 :             aChars.push_back(static_cast<sal_Char>(rPassHash[i]));
     163             : 
     164           0 :         Sequence<sal_Int8> aNewHash;
     165           0 :         SvPasswordHelper::GetHashPassword(aNewHash, &aChars[0], aChars.size());
     166           0 :         return aNewHash;
     167             :     }
     168             : 
     169           0 :     return rPassHash;
     170             : }
     171             : 
     172          12 : ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
     173             :     maOptions(nOptSize),
     174             :     mbEmptyPass(true),
     175             :     mbProtected(false),
     176             :     meHash1(PASSHASH_SHA1),
     177          12 :     meHash2(PASSHASH_UNSPECIFIED)
     178             : {
     179          12 : }
     180             : 
     181          12 : ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl& r) :
     182             :     maPassText(r.maPassText),
     183             :     maPassHash(r.maPassHash),
     184             :     maOptions(r.maOptions),
     185             :     mbEmptyPass(r.mbEmptyPass),
     186             :     mbProtected(r.mbProtected),
     187             :     meHash1(r.meHash1),
     188          12 :     meHash2(r.meHash2)
     189             : {
     190          12 : }
     191             : 
     192           0 : bool ScTableProtectionImpl::isProtected() const
     193             : {
     194           0 :     return mbProtected;
     195             : }
     196             : 
     197           0 : bool ScTableProtectionImpl::isProtectedWithPass() const
     198             : {
     199           0 :     if (!mbProtected)
     200           0 :         return false;
     201             : 
     202           0 :     return maPassText.Len() || maPassHash.getLength();
     203             : }
     204             : 
     205          12 : void ScTableProtectionImpl::setProtected(bool bProtected)
     206             : {
     207          12 :     mbProtected = bProtected;
     208             :     // We need to keep the old password even when the protection is off.  So,
     209             :     // don't erase the password data here.
     210          12 : }
     211             : 
     212           0 : void ScTableProtectionImpl::setPassword(const String& aPassText)
     213             : {
     214             :     // We can't hash it here because we don't know whether this document will
     215             :     // get saved to Excel or ODF, depending on which we will need to use a
     216             :     // different hashing algorithm.  One alternative is to hash it using all
     217             :     // hash algorithms that we support, and store them all.
     218             : 
     219           0 :     maPassText = aPassText;
     220           0 :     mbEmptyPass = aPassText.Len() == 0;
     221           0 :     if (mbEmptyPass)
     222             :     {
     223           0 :         maPassHash = Sequence<sal_Int8>();
     224             :     }
     225           0 : }
     226             : 
     227           0 : bool ScTableProtectionImpl::isPasswordEmpty() const
     228             : {
     229           0 :     return mbEmptyPass;
     230             : }
     231             : 
     232           0 : bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
     233             : {
     234           0 :     if (mbEmptyPass)
     235           0 :         return true;
     236             : 
     237           0 :     if (maPassText.Len())
     238           0 :         return true;
     239             : 
     240           0 :     if (meHash1 == eHash)
     241             :     {
     242           0 :         if (meHash2 == PASSHASH_UNSPECIFIED)
     243             :             // single hash.
     244           0 :             return true;
     245             : 
     246           0 :         return meHash2 == eHash2;
     247             :     }
     248             : 
     249           0 :     return false;
     250             : }
     251             : 
     252           0 : Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(
     253             :     ScPasswordHash eHash, ScPasswordHash eHash2) const
     254             : {
     255           0 :     Sequence<sal_Int8> aPassHash;
     256             : 
     257           0 :     if (mbEmptyPass)
     258             :         // Flaged as empty.
     259           0 :         return aPassHash;
     260             : 
     261           0 :     if (maPassText.Len())
     262             :     {
     263             :         // Cleartext password exists.  Hash it.
     264           0 :         aPassHash = hashPassword(maPassText, eHash);
     265           0 :         if (eHash2 != PASSHASH_UNSPECIFIED)
     266             :             // Double-hash it.
     267           0 :             aPassHash = hashPassword(aPassHash, eHash2);
     268             : 
     269           0 :         return aPassHash;
     270             :     }
     271             :     else
     272             :     {
     273             :         // No clear text password.  Check if we have a hash value of the right hash type.
     274           0 :         if (meHash1 == eHash)
     275             :         {
     276           0 :             aPassHash = maPassHash;
     277             : 
     278           0 :             if (meHash2 == eHash2)
     279             :                 // Matching double-hash requested.
     280           0 :                 return aPassHash;
     281           0 :             else if (meHash2 == PASSHASH_UNSPECIFIED)
     282             :                 // primary hashing type match.  Double hash it by the requested
     283             :                 // double-hash type.
     284           0 :                 return hashPassword(aPassHash, eHash2);
     285             :         }
     286             :     }
     287             : 
     288             :     // failed.
     289           0 :     return Sequence<sal_Int8>();
     290             : }
     291             : 
     292           0 : void ScTableProtectionImpl::setPasswordHash(
     293             :     const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
     294             : {
     295           0 :     sal_Int32 nLen = aPassword.getLength();
     296           0 :     mbEmptyPass = nLen <= 0 ? true : false;
     297           0 :     meHash1 = eHash;
     298           0 :     meHash2 = eHash2;
     299           0 :     maPassHash = aPassword;
     300             : 
     301             : #if DEBUG_TAB_PROTECTION
     302             :     for (sal_Int32 i = 0; i < nLen; ++i)
     303             :         printf("%2.2X ", static_cast<sal_uInt8>(aPassword[i]));
     304             :     printf("\n");
     305             : #endif
     306           0 : }
     307             : 
     308           0 : bool ScTableProtectionImpl::verifyPassword(const String& aPassText) const
     309             : {
     310             : #if DEBUG_TAB_PROTECTION
     311             :     fprintf(stdout, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
     312             :             OUStringToOString(rtl::OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr());
     313             : #endif
     314             : 
     315           0 :     if (mbEmptyPass)
     316           0 :         return aPassText.Len() == 0;
     317             : 
     318           0 :     if (maPassText.Len())
     319             :         // Clear text password exists, and this one takes precedence.
     320           0 :         return aPassText.Equals(maPassText);
     321             : 
     322           0 :     Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash1);
     323           0 :     aHash = hashPassword(aHash, meHash2);
     324             : 
     325             : #if DEBUG_TAB_PROTECTION
     326             :     fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
     327             :     for (sal_Int32 i = 0; i < aHash.getLength(); ++i)
     328             :         printf("%2.2X ", static_cast<sal_uInt8>(aHash[i]));
     329             :     printf("\n");
     330             : #endif
     331             : 
     332           0 :     return aHash == maPassHash;
     333             : }
     334             : 
     335           0 : bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
     336             : {
     337           0 :     if ( maOptions.size() <= static_cast<size_t>(nOptId) )
     338             :     {
     339             :         OSL_FAIL("ScTableProtectionImpl::isOptionEnabled: wrong size");
     340           0 :         return false;
     341             :     }
     342             : 
     343           0 :     return maOptions[nOptId];
     344             : }
     345             : 
     346         190 : void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
     347             : {
     348         190 :     if ( maOptions.size() <= static_cast<size_t>(nOptId) )
     349             :     {
     350             :         OSL_FAIL("ScTableProtectionImpl::setOption: wrong size");
     351         190 :         return;
     352             :     }
     353             : 
     354         190 :     maOptions[nOptId] = bEnabled;
     355             : }
     356             : 
     357             : // ============================================================================
     358             : 
     359           1 : ScDocProtection::ScDocProtection() :
     360           1 :     mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScDocProtection::NONE)))
     361             : {
     362           1 : }
     363             : 
     364           1 : ScDocProtection::ScDocProtection(const ScDocProtection& r) :
     365             :     ScPassHashProtectable(),
     366           1 :     mpImpl(new ScTableProtectionImpl(*r.mpImpl))
     367             : {
     368           1 : }
     369             : 
     370           4 : ScDocProtection::~ScDocProtection()
     371             : {
     372           4 : }
     373             : 
     374           0 : bool ScDocProtection::isProtected() const
     375             : {
     376           0 :     return mpImpl->isProtected();
     377             : }
     378             : 
     379           0 : bool ScDocProtection::isProtectedWithPass() const
     380             : {
     381           0 :     return mpImpl->isProtectedWithPass();
     382             : }
     383             : 
     384           1 : void ScDocProtection::setProtected(bool bProtected)
     385             : {
     386           1 :     mpImpl->setProtected(bProtected);
     387             : 
     388             :     // Currently Calc doesn't support document protection options.  So, let's
     389             :     // assume that when the document is protected, its structure is protected.
     390             :     // We need to do this for Excel export.
     391           1 :     mpImpl->setOption(ScDocProtection::STRUCTURE, bProtected);
     392           1 : }
     393             : 
     394           0 : bool ScDocProtection::isPasswordEmpty() const
     395             : {
     396           0 :     return mpImpl->isPasswordEmpty();
     397             : }
     398             : 
     399           0 : bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
     400             : {
     401           0 :     return mpImpl->hasPasswordHash(eHash, eHash2);
     402             : }
     403             : 
     404           0 : void ScDocProtection::setPassword(const String& aPassText)
     405             : {
     406           0 :     mpImpl->setPassword(aPassText);
     407           0 : }
     408             : 
     409           0 : uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
     410             : {
     411           0 :     return mpImpl->getPasswordHash(eHash, eHash2);
     412             : }
     413             : 
     414           0 : void ScDocProtection::setPasswordHash(
     415             :     const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
     416             : {
     417           0 :     mpImpl->setPasswordHash(aPassword, eHash, eHash2);
     418           0 : }
     419             : 
     420           0 : bool ScDocProtection::verifyPassword(const String& aPassText) const
     421             : {
     422           0 :     return mpImpl->verifyPassword(aPassText);
     423             : }
     424             : 
     425           0 : bool ScDocProtection::isOptionEnabled(Option eOption) const
     426             : {
     427           0 :     return mpImpl->isOptionEnabled(eOption);
     428             : }
     429             : 
     430           2 : void ScDocProtection::setOption(Option eOption, bool bEnabled)
     431             : {
     432           2 :     mpImpl->setOption(eOption, bEnabled);
     433           2 : }
     434             : 
     435             : // ============================================================================
     436             : 
     437          11 : ScTableProtection::ScTableProtection() :
     438          11 :     mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScTableProtection::NONE)))
     439             : {
     440             :     // Set default values for the options.
     441          11 :     mpImpl->setOption(SELECT_LOCKED_CELLS,   true);
     442          11 :     mpImpl->setOption(SELECT_UNLOCKED_CELLS, true);
     443          11 : }
     444             : 
     445          11 : ScTableProtection::ScTableProtection(const ScTableProtection& r) :
     446             :     ScPassHashProtectable(),
     447          11 :     mpImpl(new ScTableProtectionImpl(*r.mpImpl))
     448             : {
     449          11 : }
     450             : 
     451          44 : ScTableProtection::~ScTableProtection()
     452             : {
     453          44 : }
     454             : 
     455           0 : bool ScTableProtection::isProtected() const
     456             : {
     457           0 :     return mpImpl->isProtected();
     458             : }
     459             : 
     460           0 : bool ScTableProtection::isProtectedWithPass() const
     461             : {
     462           0 :     return mpImpl->isProtectedWithPass();
     463             : }
     464             : 
     465          11 : void ScTableProtection::setProtected(bool bProtected)
     466             : {
     467          11 :     mpImpl->setProtected(bProtected);
     468          11 : }
     469             : 
     470           0 : bool ScTableProtection::isPasswordEmpty() const
     471             : {
     472           0 :     return mpImpl->isPasswordEmpty();
     473             : }
     474             : 
     475           0 : bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
     476             : {
     477           0 :     return mpImpl->hasPasswordHash(eHash, eHash2);
     478             : }
     479             : 
     480           0 : void ScTableProtection::setPassword(const String& aPassText)
     481             : {
     482           0 :     mpImpl->setPassword(aPassText);
     483           0 : }
     484             : 
     485           0 : Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
     486             : {
     487           0 :     return mpImpl->getPasswordHash(eHash, eHash2);
     488             : }
     489             : 
     490           0 : void ScTableProtection::setPasswordHash(
     491             :     const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
     492             : {
     493           0 :     mpImpl->setPasswordHash(aPassword, eHash, eHash2);
     494           0 : }
     495             : 
     496           0 : bool ScTableProtection::verifyPassword(const String& aPassText) const
     497             : {
     498           0 :     return mpImpl->verifyPassword(aPassText);
     499             : }
     500             : 
     501           0 : bool ScTableProtection::isOptionEnabled(Option eOption) const
     502             : {
     503           0 :     return mpImpl->isOptionEnabled(eOption);
     504             : }
     505             : 
     506         165 : void ScTableProtection::setOption(Option eOption, bool bEnabled)
     507             : {
     508         165 :     mpImpl->setOption(eOption, bEnabled);
     509         165 : }
     510             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10