xref: /trunk/main/sc/source/core/data/tabprotection.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 // INCLUDE ---------------------------------------------------------------
32 
33 #include "tabprotection.hxx"
34 #include "tools/debug.hxx"
35 #include "svl/PasswordHelper.hxx"
36 #include <comphelper/docpasswordhelper.hxx>
37 #include "document.hxx"
38 
39 #define DEBUG_TAB_PROTECTION 0
40 
41 using namespace ::com::sun::star;
42 using ::com::sun::star::uno::Sequence;
43 using ::rtl::OUString;
44 
45 // ============================================================================
46 
47 bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash)
48 {
49     if (rDoc.IsDocProtected())
50     {
51         const ScDocProtection* p = rDoc.GetDocProtection();
52         if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash))
53             return true;
54     }
55 
56     SCTAB nTabCount = rDoc.GetTableCount();
57     for (SCTAB i = 0; i < nTabCount; ++i)
58     {
59         const ScTableProtection* p = rDoc.GetTabProtection(i);
60         if (!p || !p->isProtected())
61             // Sheet not protected.  Skip it.
62             continue;
63 
64         if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash))
65             return true;
66     }
67 
68     return false;
69 }
70 
71 // ============================================================================
72 
73 ScPassHashProtectable::~ScPassHashProtectable()
74 {
75 }
76 
77 // ============================================================================
78 
79 class ScTableProtectionImpl
80 {
81 public:
82     static ::com::sun::star::uno::Sequence<sal_Int8> hashPassword(const String& aPassText, ScPasswordHash eHash = PASSHASH_OOO);
83 
84     explicit ScTableProtectionImpl(SCSIZE nOptSize);
85     explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
86 
87     bool isProtected() const;
88     bool isProtectedWithPass() const;
89     void setProtected(bool bProtected);
90 
91     bool isPasswordEmpty() const;
92     bool hasPasswordHash(ScPasswordHash eHash) const;
93     void setPassword(const String& aPassText);
94     ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const;
95     void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash = PASSHASH_OOO);
96     bool verifyPassword(const String& aPassText) const;
97 
98     bool isOptionEnabled(SCSIZE nOptId) const;
99     void setOption(SCSIZE nOptId, bool bEnabled);
100 
101 private:
102     String maPassText;
103     ::com::sun::star::uno::Sequence<sal_Int8>   maPassHash;
104     ::std::vector<bool> maOptions;
105     bool mbEmptyPass;
106     bool mbProtected;
107     ScPasswordHash meHash;
108 };
109 
110 Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const String& aPassText, ScPasswordHash eHash)
111 {
112     Sequence<sal_Int8> aHash;
113     switch (eHash)
114     {
115         case PASSHASH_XL:
116             aHash = ::comphelper::DocPasswordHelper::GetXLHashAsSequence( aPassText, RTL_TEXTENCODING_UTF8 );
117         break;
118         case PASSHASH_OOO:
119         default:
120             SvPasswordHelper::GetHashPassword(aHash, aPassText);
121         break;
122     }
123     return aHash;
124 }
125 
126 ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
127     maOptions(nOptSize),
128     mbEmptyPass(true),
129     mbProtected(false),
130     meHash(PASSHASH_OOO)
131 {
132 }
133 
134 ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl& r) :
135     maPassText(r.maPassText),
136     maPassHash(r.maPassHash),
137     maOptions(r.maOptions),
138     mbEmptyPass(r.mbEmptyPass),
139     mbProtected(r.mbProtected),
140     meHash(r.meHash)
141 {
142 }
143 
144 bool ScTableProtectionImpl::isProtected() const
145 {
146     return mbProtected;
147 }
148 
149 bool ScTableProtectionImpl::isProtectedWithPass() const
150 {
151     if (!mbProtected)
152         return false;
153 
154     return maPassText.Len() || maPassHash.getLength();
155 }
156 
157 void ScTableProtectionImpl::setProtected(bool bProtected)
158 {
159     mbProtected = bProtected;
160     // We need to keep the old password even when the protection is off.  So,
161     // don't erase the password data here.
162 }
163 
164 void ScTableProtectionImpl::setPassword(const String& aPassText)
165 {
166     // We can't hash it here because we don't know whether this document will
167     // get saved to Excel or ODF, depending on which we will need to use a
168     // different hashing algorithm.  One alternative is to hash it using all
169     // hash algorithms that we support, and store them all.
170 
171     maPassText = aPassText;
172     mbEmptyPass = aPassText.Len() == 0;
173     if (mbEmptyPass)
174     {
175         maPassHash = Sequence<sal_Int8>();
176     }
177 }
178 
179 bool ScTableProtectionImpl::isPasswordEmpty() const
180 {
181     return mbEmptyPass;
182 }
183 
184 bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash) const
185 {
186     if (mbEmptyPass)
187         return true;
188 
189     if (maPassText.Len())
190         return true;
191 
192     if (meHash == eHash)
193         return true;
194 
195     return false;
196 }
197 
198 Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(ScPasswordHash eHash) const
199 {
200     if (mbEmptyPass)
201         // Flaged as empty.
202         return Sequence<sal_Int8>();
203 
204     if (maPassText.Len())
205         // Cleartext password exists.  Hash it.
206         return hashPassword(maPassText, eHash);
207 
208     if (meHash == eHash)
209         // Stored hash exists.
210         return maPassHash;
211 
212     // Failed to find a matching hash.
213     return Sequence<sal_Int8>();
214 }
215 
216 void ScTableProtectionImpl::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
217 {
218     sal_Int32 nLen = aPassword.getLength();
219     mbEmptyPass = nLen <= 0 ? true : false;
220     meHash = eHash;
221     maPassHash = aPassword;
222 
223 #if DEBUG_TAB_PROTECTION
224     for (sal_Int32 i = 0; i < nLen; ++i)
225         printf("%2.2X ", static_cast<sal_uInt8>(aPassword[i]));
226     printf("\n");
227 #endif
228 }
229 
230 bool ScTableProtectionImpl::verifyPassword(const String& aPassText) const
231 {
232 #if DEBUG_TAB_PROTECTION
233     fprintf(stdout, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
234             OUStringToOString(rtl::OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr());
235 #endif
236 
237     if (mbEmptyPass)
238         return aPassText.Len() == 0;
239 
240     if (maPassText.Len())
241         // Clear text password exists, and this one takes precedence.
242         return aPassText.Equals(maPassText);
243 
244     Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash);
245 
246 #if DEBUG_TAB_PROTECTION
247     fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
248     for (sal_Int32 i = 0; i < aHash.getLength(); ++i)
249         printf("%2.2X ", static_cast<sal_uInt8>(aHash[i]));
250     printf("\n");
251 #endif
252 
253     return aHash == maPassHash;
254 }
255 
256 bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
257 {
258     if ( maOptions.size() <= static_cast<size_t>(nOptId) )
259     {
260         DBG_ERROR("ScTableProtectionImpl::isOptionEnabled: wrong size");
261         return false;
262     }
263 
264     return maOptions[nOptId];
265 }
266 
267 void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
268 {
269     if ( maOptions.size() <= static_cast<size_t>(nOptId) )
270     {
271         DBG_ERROR("ScTableProtectionImpl::setOption: wrong size");
272         return;
273     }
274 
275     maOptions[nOptId] = bEnabled;
276 }
277 
278 // ============================================================================
279 
280 ScDocProtection::ScDocProtection() :
281     mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScDocProtection::NONE)))
282 {
283 }
284 
285 ScDocProtection::ScDocProtection(const ScDocProtection& r) :
286     ScPassHashProtectable(),
287     mpImpl(new ScTableProtectionImpl(*r.mpImpl))
288 {
289 }
290 
291 ScDocProtection::~ScDocProtection()
292 {
293 }
294 
295 bool ScDocProtection::isProtected() const
296 {
297     return mpImpl->isProtected();
298 }
299 
300 bool ScDocProtection::isProtectedWithPass() const
301 {
302     return mpImpl->isProtectedWithPass();
303 }
304 
305 void ScDocProtection::setProtected(bool bProtected)
306 {
307     mpImpl->setProtected(bProtected);
308 
309     // Currently Calc doesn't support document protection options.  So, let's
310     // assume that when the document is protected, its structure is protected.
311     // We need to do this for Excel export.
312     mpImpl->setOption(ScDocProtection::STRUCTURE, bProtected);
313 }
314 
315 bool ScDocProtection::isPasswordEmpty() const
316 {
317     return mpImpl->isPasswordEmpty();
318 }
319 
320 bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash) const
321 {
322     return mpImpl->hasPasswordHash(eHash);
323 }
324 
325 void ScDocProtection::setPassword(const String& aPassText)
326 {
327     mpImpl->setPassword(aPassText);
328 }
329 
330 uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash) const
331 {
332     return mpImpl->getPasswordHash(eHash);
333 }
334 
335 void ScDocProtection::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
336 {
337     mpImpl->setPasswordHash(aPassword, eHash);
338 }
339 
340 bool ScDocProtection::verifyPassword(const String& aPassText) const
341 {
342     return mpImpl->verifyPassword(aPassText);
343 }
344 
345 bool ScDocProtection::isOptionEnabled(Option eOption) const
346 {
347     return mpImpl->isOptionEnabled(eOption);
348 }
349 
350 void ScDocProtection::setOption(Option eOption, bool bEnabled)
351 {
352     mpImpl->setOption(eOption, bEnabled);
353 }
354 
355 // ============================================================================
356 
357 ScTableProtection::ScTableProtection() :
358     mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScTableProtection::NONE)))
359 {
360     // Set default values for the options.
361     mpImpl->setOption(SELECT_LOCKED_CELLS,   true);
362     mpImpl->setOption(SELECT_UNLOCKED_CELLS, true);
363 }
364 
365 ScTableProtection::ScTableProtection(const ScTableProtection& r) :
366     ScPassHashProtectable(),
367     mpImpl(new ScTableProtectionImpl(*r.mpImpl))
368 {
369 }
370 
371 ScTableProtection::~ScTableProtection()
372 {
373 }
374 
375 bool ScTableProtection::isProtected() const
376 {
377     return mpImpl->isProtected();
378 }
379 
380 bool ScTableProtection::isProtectedWithPass() const
381 {
382     return mpImpl->isProtectedWithPass();
383 }
384 
385 void ScTableProtection::setProtected(bool bProtected)
386 {
387     mpImpl->setProtected(bProtected);
388 }
389 
390 bool ScTableProtection::isPasswordEmpty() const
391 {
392     return mpImpl->isPasswordEmpty();
393 }
394 
395 bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash) const
396 {
397     return mpImpl->hasPasswordHash(eHash);
398 }
399 
400 void ScTableProtection::setPassword(const String& aPassText)
401 {
402     mpImpl->setPassword(aPassText);
403 }
404 
405 Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash) const
406 {
407     return mpImpl->getPasswordHash(eHash);
408 }
409 
410 void ScTableProtection::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
411 {
412     mpImpl->setPasswordHash(aPassword, eHash);
413 }
414 
415 bool ScTableProtection::verifyPassword(const String& aPassText) const
416 {
417     return mpImpl->verifyPassword(aPassText);
418 }
419 
420 bool ScTableProtection::isOptionEnabled(Option eOption) const
421 {
422     return mpImpl->isOptionEnabled(eOption);
423 }
424 
425 void ScTableProtection::setOption(Option eOption, bool bEnabled)
426 {
427     mpImpl->setOption(eOption, bEnabled);
428 }
429 
430