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