fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / tabprotection.cxx
blob6ee899d82a3378f4eef19d8502138c03d68317e5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "tabprotection.hxx"
21 #include <svl/PasswordHelper.hxx>
22 #include <comphelper/docpasswordhelper.hxx>
23 #include <osl/diagnose.h>
24 #include "document.hxx"
26 #include <vector>
28 #define DEBUG_TAB_PROTECTION 0
30 #define URI_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1"
31 #define URI_XLS_LEGACY "http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"
33 using namespace ::com::sun::star;
34 using ::com::sun::star::uno::Sequence;
35 using ::std::vector;
37 bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash1, ScPasswordHash eHash2)
39 if (rDoc.IsDocProtected())
41 const ScDocProtection* p = rDoc.GetDocProtection();
42 if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
43 return true;
46 SCTAB nTabCount = rDoc.GetTableCount();
47 for (SCTAB i = 0; i < nTabCount; ++i)
49 const ScTableProtection* p = rDoc.GetTabProtection(i);
50 if (!p || !p->isProtected())
51 // Sheet not protected. Skip it.
52 continue;
54 if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
55 return true;
58 return false;
61 OUString ScPassHashHelper::getHashURI(ScPasswordHash eHash)
63 switch (eHash)
65 case PASSHASH_SHA1:
66 return OUString(URI_SHA1);
67 case PASSHASH_XL:
68 return OUString(URI_XLS_LEGACY);
69 case PASSHASH_UNSPECIFIED:
70 default:
73 return OUString();
76 ScPasswordHash ScPassHashHelper::getHashTypeFromURI(const OUString& rURI)
78 if ( rURI == URI_SHA1 )
79 return PASSHASH_SHA1;
80 else if ( rURI == URI_XLS_LEGACY )
81 return PASSHASH_XL;
82 return PASSHASH_UNSPECIFIED;
85 ScPassHashProtectable::~ScPassHashProtectable()
89 class ScTableProtectionImpl
91 public:
92 static Sequence<sal_Int8> hashPassword(const OUString& aPassText, ScPasswordHash eHash = PASSHASH_SHA1);
93 static Sequence<sal_Int8> hashPassword(const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash = PASSHASH_SHA1);
95 explicit ScTableProtectionImpl(SCSIZE nOptSize);
96 explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
98 bool isProtected() const { return mbProtected;}
99 bool isProtectedWithPass() const;
100 void setProtected(bool bProtected);
102 bool isPasswordEmpty() const { return mbEmptyPass;}
103 bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
104 void setPassword(const OUString& aPassText);
105 ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(
106 ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
107 void setPasswordHash(
108 const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
109 ScPasswordHash eHash = PASSHASH_SHA1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED);
110 bool verifyPassword(const OUString& aPassText) const;
112 bool isOptionEnabled(SCSIZE nOptId) const;
113 void setOption(SCSIZE nOptId, bool bEnabled);
115 void setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt );
116 const ::std::vector< ScEnhancedProtection > & getEnhancedProtection() const { return maEnhancedProtection;}
117 bool updateReference( UpdateRefMode, ScDocument*, const ScRange& rWhere, SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
118 bool isBlockEditable( const ScRange& rRange ) const;
119 bool isSelectionEditable( const ScRangeList& rRangeList ) const;
121 private:
122 OUString maPassText;
123 ::com::sun::star::uno::Sequence<sal_Int8> maPassHash;
124 ::std::vector<bool> maOptions;
125 bool mbEmptyPass;
126 bool mbProtected;
127 ScPasswordHash meHash1;
128 ScPasswordHash meHash2;
129 ::std::vector< ScEnhancedProtection > maEnhancedProtection;
132 Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const OUString& aPassText, ScPasswordHash eHash)
134 Sequence<sal_Int8> aHash;
135 switch (eHash)
137 case PASSHASH_XL:
138 aHash = ::comphelper::DocPasswordHelper::GetXLHashAsSequence( aPassText, RTL_TEXTENCODING_UTF8 );
139 break;
140 case PASSHASH_SHA1:
141 SvPasswordHelper::GetHashPassword(aHash, aPassText);
142 break;
143 default:
146 return aHash;
149 Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(
150 const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash)
152 if (!rPassHash.getLength() || eHash == PASSHASH_UNSPECIFIED)
153 return rPassHash;
155 // TODO: Right now, we only support double-hash by SHA1.
156 if (eHash == PASSHASH_SHA1)
158 vector<sal_Char> aChars;
159 sal_Int32 n = rPassHash.getLength();
160 aChars.reserve(n);
161 for (sal_Int32 i = 0; i < n; ++i)
162 aChars.push_back(static_cast<sal_Char>(rPassHash[i]));
164 Sequence<sal_Int8> aNewHash;
165 SvPasswordHelper::GetHashPassword(aNewHash, &aChars[0], aChars.size());
166 return aNewHash;
169 return rPassHash;
172 ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
173 maOptions(nOptSize),
174 mbEmptyPass(true),
175 mbProtected(false),
176 meHash1(PASSHASH_SHA1),
177 meHash2(PASSHASH_UNSPECIFIED)
181 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 meHash2(r.meHash2),
189 maEnhancedProtection(r.maEnhancedProtection)
193 bool ScTableProtectionImpl::isProtectedWithPass() const
195 if (!mbProtected)
196 return false;
198 return !maPassText.isEmpty() || maPassHash.getLength();
201 void ScTableProtectionImpl::setProtected(bool bProtected)
203 mbProtected = bProtected;
204 // We need to keep the old password even when the protection is off. So,
205 // don't erase the password data here.
208 void ScTableProtectionImpl::setPassword(const OUString& aPassText)
210 // We can't hash it here because we don't know whether this document will
211 // get saved to Excel or ODF, depending on which we will need to use a
212 // different hashing algorithm. One alternative is to hash it using all
213 // hash algorithms that we support, and store them all.
215 maPassText = aPassText;
216 mbEmptyPass = aPassText.isEmpty();
217 if (mbEmptyPass)
219 maPassHash = Sequence<sal_Int8>();
223 bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
225 if (mbEmptyPass)
226 return true;
228 if (!maPassText.isEmpty())
229 return true;
231 if (meHash1 == eHash)
233 if (meHash2 == PASSHASH_UNSPECIFIED)
234 // single hash.
235 return true;
237 return meHash2 == eHash2;
240 return false;
243 Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(
244 ScPasswordHash eHash, ScPasswordHash eHash2) const
246 Sequence<sal_Int8> aPassHash;
248 if (mbEmptyPass)
249 // Flaged as empty.
250 return aPassHash;
252 if (!maPassText.isEmpty())
254 // Cleartext password exists. Hash it.
255 aPassHash = hashPassword(maPassText, eHash);
256 if (eHash2 != PASSHASH_UNSPECIFIED)
257 // Double-hash it.
258 aPassHash = hashPassword(aPassHash, eHash2);
260 return aPassHash;
262 else
264 // No clear text password. Check if we have a hash value of the right hash type.
265 if (meHash1 == eHash)
267 aPassHash = maPassHash;
269 if (meHash2 == eHash2)
270 // Matching double-hash requested.
271 return aPassHash;
272 else if (meHash2 == PASSHASH_UNSPECIFIED)
273 // primary hashing type match. Double hash it by the requested
274 // double-hash type.
275 return hashPassword(aPassHash, eHash2);
279 // failed.
280 return Sequence<sal_Int8>();
283 void ScTableProtectionImpl::setPasswordHash(
284 const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
286 sal_Int32 nLen = aPassword.getLength();
287 mbEmptyPass = nLen <= 0;
288 meHash1 = eHash;
289 meHash2 = eHash2;
290 maPassHash = aPassword;
292 #if DEBUG_TAB_PROTECTION
293 for (sal_Int32 i = 0; i < nLen; ++i)
294 printf("%2.2X ", static_cast<sal_uInt8>(aPassword[i]));
295 printf("\n");
296 #endif
299 bool ScTableProtectionImpl::verifyPassword(const OUString& aPassText) const
301 #if DEBUG_TAB_PROTECTION
302 fprintf(stdout, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
303 OUStringToOString(OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr());
304 #endif
306 if (mbEmptyPass)
307 return aPassText.isEmpty();
309 if (!maPassText.isEmpty())
310 // Clear text password exists, and this one takes precedence.
311 return aPassText == maPassText;
313 Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash1);
314 aHash = hashPassword(aHash, meHash2);
316 #if DEBUG_TAB_PROTECTION
317 fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
318 for (sal_Int32 i = 0; i < aHash.getLength(); ++i)
319 printf("%2.2X ", static_cast<sal_uInt8>(aHash[i]));
320 printf("\n");
321 #endif
323 return aHash == maPassHash;
326 bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
328 if ( maOptions.size() <= static_cast<size_t>(nOptId) )
330 OSL_FAIL("ScTableProtectionImpl::isOptionEnabled: wrong size");
331 return false;
334 return maOptions[nOptId];
337 void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
339 if ( maOptions.size() <= static_cast<size_t>(nOptId) )
341 OSL_FAIL("ScTableProtectionImpl::setOption: wrong size");
342 return;
345 maOptions[nOptId] = bEnabled;
348 void ScTableProtectionImpl::setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt )
350 maEnhancedProtection = rProt;
353 bool ScTableProtectionImpl::updateReference( UpdateRefMode eMode, ScDocument* pDoc,
354 const ScRange& rWhere, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
356 bool bChanged = false;
357 for (::std::vector<ScEnhancedProtection>::iterator it(maEnhancedProtection.begin());
358 it != maEnhancedProtection.end(); ++it)
360 if ((*it).maRangeList.Is())
361 bChanged |= (*it).maRangeList->UpdateReference( eMode, pDoc, rWhere, nDx, nDy, nDz);
363 return bChanged;
366 bool ScTableProtectionImpl::isBlockEditable( const ScRange& rRange ) const
368 /* TODO: ask for password (and remember) if a password was set for
369 * a matching range and no matching range without password was encountered.
370 * Would need another return type than boolean to reflect
371 * "password required for a specific protection". */
373 // No protection exception or overriding permission to edit if empty.
374 if (maEnhancedProtection.empty())
375 return false;
377 // No security descriptor in an enhanced protection means the ranges of
378 // that protection are editable. If there is any security descriptor
379 // present we assume the permission to edit is not granted. Until we
380 // actually can evaluate the descriptors..
382 for (::std::vector<ScEnhancedProtection>::const_iterator it(maEnhancedProtection.begin()),
383 itEnd(maEnhancedProtection.end()); it != itEnd; ++it)
385 if (!(*it).hasSecurityDescriptor() && (*it).maRangeList.Is())
387 if ((*it).maRangeList->In( rRange))
389 // Range is editable if no password is assigned.
390 if (!(*it).hasPassword())
391 return true;
396 // For a single address, a simple check with single ranges was sufficient.
397 if (rRange.aStart == rRange.aEnd)
398 return false;
400 // Test also for cases where rRange is encompassed by a union of two or
401 // more ranges of the list. The original ranges are not necessarily joined.
402 for (::std::vector<ScEnhancedProtection>::const_iterator it(maEnhancedProtection.begin()),
403 itEnd(maEnhancedProtection.end()); it != itEnd; ++it)
405 if (!(*it).hasSecurityDescriptor() && (*it).maRangeList.Is())
407 ScRangeList aList( (*it).maRangeList->GetIntersectedRange( rRange));
408 if (aList.size() == 1 && *aList[0] == rRange)
410 // Range is editable if no password is assigned.
411 if (!(*it).hasPassword())
412 return true;
417 // Ranges may even be distributed over different protection records, for
418 // example if they are assigned different names, and can have different
419 // passwords. Combine the ones that can be edited.
420 /* TODO: once we handle passwords, remember a successful unlock at
421 * ScEnhancedProtection so we can use that here. */
422 ScRangeList aRangeList;
423 for (::std::vector<ScEnhancedProtection>::const_iterator it(maEnhancedProtection.begin()),
424 itEnd(maEnhancedProtection.end()); it != itEnd; ++it)
426 if (!(*it).hasSecurityDescriptor() && (*it).maRangeList.Is())
428 // Ranges are editable if no password is assigned.
429 if (!(*it).hasPassword())
431 const ScRangeList& rRanges = *(*it).maRangeList;
432 size_t nRanges = rRanges.size();
433 for (size_t i=0; i < nRanges; ++i)
435 aRangeList.Append( *rRanges[i]);
440 ScRangeList aResultList( aRangeList.GetIntersectedRange( rRange));
441 if (aResultList.size() == 1 && *aResultList[0] == rRange)
442 return true;
444 return false;
447 bool ScTableProtectionImpl::isSelectionEditable( const ScRangeList& rRangeList ) const
449 if (rRangeList.empty())
450 return false;
452 for (size_t i=0, nRanges = rRangeList.size(); i < nRanges; ++i)
454 if (!isBlockEditable( *rRangeList[i]))
455 return false;
457 return true;
460 ScDocProtection::ScDocProtection() :
461 mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScDocProtection::NONE)))
465 ScDocProtection::ScDocProtection(const ScDocProtection& r) :
466 ScPassHashProtectable(),
467 mpImpl(new ScTableProtectionImpl(*r.mpImpl))
471 ScDocProtection::~ScDocProtection()
475 bool ScDocProtection::isProtected() const
477 return mpImpl->isProtected();
480 bool ScDocProtection::isProtectedWithPass() const
482 return mpImpl->isProtectedWithPass();
485 void ScDocProtection::setProtected(bool bProtected)
487 mpImpl->setProtected(bProtected);
489 // Currently Calc doesn't support document protection options. So, let's
490 // assume that when the document is protected, its structure is protected.
491 // We need to do this for Excel export.
492 mpImpl->setOption(ScDocProtection::STRUCTURE, bProtected);
495 bool ScDocProtection::isPasswordEmpty() const
497 return mpImpl->isPasswordEmpty();
500 bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
502 return mpImpl->hasPasswordHash(eHash, eHash2);
505 void ScDocProtection::setPassword(const OUString& aPassText)
507 mpImpl->setPassword(aPassText);
510 uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
512 return mpImpl->getPasswordHash(eHash, eHash2);
515 void ScDocProtection::setPasswordHash(
516 const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
518 mpImpl->setPasswordHash(aPassword, eHash, eHash2);
521 bool ScDocProtection::verifyPassword(const OUString& aPassText) const
523 return mpImpl->verifyPassword(aPassText);
526 bool ScDocProtection::isOptionEnabled(Option eOption) const
528 return mpImpl->isOptionEnabled(eOption);
531 void ScDocProtection::setOption(Option eOption, bool bEnabled)
533 mpImpl->setOption(eOption, bEnabled);
536 ScTableProtection::ScTableProtection() :
537 mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScTableProtection::NONE)))
539 // Set default values for the options.
540 mpImpl->setOption(SELECT_LOCKED_CELLS, true);
541 mpImpl->setOption(SELECT_UNLOCKED_CELLS, true);
544 ScTableProtection::ScTableProtection(const ScTableProtection& r) :
545 ScPassHashProtectable(),
546 mpImpl(new ScTableProtectionImpl(*r.mpImpl))
550 ScTableProtection::~ScTableProtection()
554 bool ScTableProtection::isProtected() const
556 return mpImpl->isProtected();
559 bool ScTableProtection::isProtectedWithPass() const
561 return mpImpl->isProtectedWithPass();
564 void ScTableProtection::setProtected(bool bProtected)
566 mpImpl->setProtected(bProtected);
569 bool ScTableProtection::isPasswordEmpty() const
571 return mpImpl->isPasswordEmpty();
574 bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
576 return mpImpl->hasPasswordHash(eHash, eHash2);
579 void ScTableProtection::setPassword(const OUString& aPassText)
581 mpImpl->setPassword(aPassText);
584 Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
586 return mpImpl->getPasswordHash(eHash, eHash2);
589 void ScTableProtection::setPasswordHash(
590 const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
592 mpImpl->setPasswordHash(aPassword, eHash, eHash2);
595 bool ScTableProtection::verifyPassword(const OUString& aPassText) const
597 return mpImpl->verifyPassword(aPassText);
600 bool ScTableProtection::isOptionEnabled(Option eOption) const
602 return mpImpl->isOptionEnabled(eOption);
605 void ScTableProtection::setOption(Option eOption, bool bEnabled)
607 mpImpl->setOption(eOption, bEnabled);
610 void ScTableProtection::setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt )
612 mpImpl->setEnhancedProtection(rProt);
615 const ::std::vector< ScEnhancedProtection > & ScTableProtection::getEnhancedProtection() const
617 return mpImpl->getEnhancedProtection();
620 bool ScTableProtection::updateReference( UpdateRefMode eMode, ScDocument* pDoc, const ScRange& rWhere,
621 SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
623 return mpImpl->updateReference( eMode, pDoc, rWhere, nDx, nDy, nDz);
626 bool ScTableProtection::isBlockEditable( const ScRange& rRange ) const
628 return mpImpl->isBlockEditable( rRange);
631 bool ScTableProtection::isSelectionEditable( const ScRangeList& rRangeList ) const
633 return mpImpl->isSelectionEditable( rRangeList);
636 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */