source: trunk/poppler/mypoppler/poppler/SecurityHandler.cc @ 27

Last change on this file since 27 was 27, checked in by Eugene Romanenko, 16 years ago

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

File size: 9.8 KB
Line 
1//========================================================================
2//
3// SecurityHandler.cc
4//
5// Copyright 2004 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <config.h>
10
11#ifdef USE_GCC_PRAGMAS
12#pragma implementation
13#endif
14
15#include "GooString.h"
16#include "PDFDoc.h"
17#include "Decrypt.h"
18#include "Error.h"
19#include "GlobalParams.h"
20#if HAVE_XPDFCORE
21#  include "XPDFCore.h"
22#elif HAVE_WINPDFCORE
23#  include "WinPDFCore.h"
24#endif
25#ifdef ENABLE_PLUGINS
26#  include "XpdfPluginAPI.h"
27#endif
28#include "SecurityHandler.h"
29#include "UGooString.h"
30
31//------------------------------------------------------------------------
32// SecurityHandler
33//------------------------------------------------------------------------
34
35SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
36  Object filterObj;
37  SecurityHandler *secHdlr;
38  XpdfSecurityHandler *xsh;
39
40  encryptDictA->dictLookup("Filter", &filterObj);
41  if (filterObj.isName("Standard")) {
42    secHdlr = new StandardSecurityHandler(docA, encryptDictA);
43  } else if (filterObj.isName()) {
44#ifdef ENABLE_PLUGINS
45    if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) {
46      secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh);
47    } else {
48#endif
49      error(-1, "Couldn't find the '%s' security handler",
50            filterObj.getName());
51      secHdlr = NULL;
52#ifdef ENABLE_PLUGINS
53    }
54#endif
55  } else {
56    error(-1, "Missing or invalid 'Filter' entry in encryption dictionary");
57    secHdlr = NULL;
58  }
59  filterObj.free();
60  return secHdlr;
61}
62
63SecurityHandler::SecurityHandler(PDFDoc *docA) {
64  doc = docA;
65}
66
67SecurityHandler::~SecurityHandler() {
68}
69
70GBool SecurityHandler::checkEncryption(GooString *ownerPassword,
71                                       GooString *userPassword) {
72  void *authData;
73  GBool ok;
74  int i;
75
76  if (ownerPassword || userPassword) {
77    authData = makeAuthData(ownerPassword, userPassword);
78  } else {
79    authData = NULL;
80  }
81  ok = authorize(authData);
82  if (authData) {
83    freeAuthData(authData);
84  }
85  for (i = 0; !ok && i < 3; ++i) {
86    if (!(authData = getAuthData())) {
87      break;
88    }
89    ok = authorize(authData);
90    if (authData) {
91      freeAuthData(authData);
92    }
93  }
94  if (!ok) {
95    error(-1, "Incorrect password");
96  }
97  return ok;
98}
99
100//------------------------------------------------------------------------
101// StandardSecurityHandler
102//------------------------------------------------------------------------
103
104class StandardAuthData {
105public:
106
107  StandardAuthData(GooString *ownerPasswordA, GooString *userPasswordA) {
108    ownerPassword = ownerPasswordA;
109    userPassword = userPasswordA;
110  }
111
112  ~StandardAuthData() {
113    if (ownerPassword) {
114      delete ownerPassword;
115    }
116    if (userPassword) {
117      delete userPassword;
118    }
119  }
120
121  GooString *ownerPassword;
122  GooString *userPassword;
123};
124
125StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
126                                                 Object *encryptDictA):
127  SecurityHandler(docA)
128{
129  Object versionObj, revisionObj, lengthObj;
130  Object ownerKeyObj, userKeyObj, permObj, fileIDObj;
131  Object fileIDObj1;
132  Object cryptFiltersObj, streamFilterObj, stringFilterObj;
133  Object cryptFilterObj, cfmObj, cfLengthObj;
134  Object encryptMetadataObj;
135
136  ok = gFalse;
137  fileID = NULL;
138  ownerKey = NULL;
139  userKey = NULL;
140
141  encryptDictA->dictLookup("V", &versionObj);
142  encryptDictA->dictLookup("R", &revisionObj);
143  encryptDictA->dictLookup("Length", &lengthObj);
144  encryptDictA->dictLookup("O", &ownerKeyObj);
145  encryptDictA->dictLookup("U", &userKeyObj);
146  encryptDictA->dictLookup("P", &permObj);
147  doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
148  if (versionObj.isInt() &&
149      revisionObj.isInt() &&
150      ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 &&
151      userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 &&
152      permObj.isInt()) {
153    encVersion = versionObj.getInt();
154    encRevision = revisionObj.getInt();
155    // revision 2 forces a 40-bit key - some buggy PDF generators
156    // set the Length value incorrectly
157    if (encRevision == 2 || !lengthObj.isInt()) {
158      fileKeyLength = 5;
159    } else {
160      fileKeyLength = lengthObj.getInt() / 8;
161    }
162    encryptMetadata = gTrue;
163    //~ this currently only handles a subset of crypt filter functionality
164    if (encVersion == 4 && encRevision == 4) {
165      encryptDictA->dictLookup("CF", &cryptFiltersObj);
166      encryptDictA->dictLookup("StmF", &streamFilterObj);
167      encryptDictA->dictLookup("StrF", &stringFilterObj);
168      if (cryptFiltersObj.isDict() &&
169          streamFilterObj.isName() &&
170          stringFilterObj.isName() &&
171          !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) {
172        if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
173                                       &cryptFilterObj)->isDict()) {
174          if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) {
175            encVersion = 2;
176            encRevision = 3;
177            if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) {
178              //~ according to the spec, this should be cfLengthObj / 8
179              fileKeyLength = cfLengthObj.getInt();
180            }
181            cfLengthObj.free();
182          }
183          cfmObj.free();
184        }
185        cryptFilterObj.free();
186      }
187      stringFilterObj.free();
188      streamFilterObj.free();
189      cryptFiltersObj.free();
190      if (encryptDictA->dictLookup("EncryptMetadata",
191                                   &encryptMetadataObj)->isBool()) {
192        encryptMetadata = encryptMetadataObj.getBool();
193      }
194      encryptMetadataObj.free();
195    }
196    permFlags = permObj.getInt();
197    ownerKey = ownerKeyObj.getString()->copy();
198    userKey = userKeyObj.getString()->copy();
199    if (encVersion >= 1 && encVersion <= 2 &&
200        encRevision >= 2 && encRevision <= 3) {
201      if (fileIDObj.isArray()) {
202        if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
203          fileID = fileIDObj1.getString()->copy();
204        } else {
205          fileID = new GooString();
206        }
207        fileIDObj1.free();
208      } else {
209        fileID = new GooString();
210      }
211      ok = gTrue;
212    } else {
213      error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
214            encVersion, encRevision);
215    }
216  } else {
217    error(-1, "Weird encryption info");
218  }
219  if (fileKeyLength > 16) {
220    fileKeyLength = 16;
221  }
222  fileIDObj.free();
223  permObj.free();
224  userKeyObj.free();
225  ownerKeyObj.free();
226  lengthObj.free();
227  revisionObj.free();
228  versionObj.free();
229}
230
231StandardSecurityHandler::~StandardSecurityHandler() {
232  if (fileID) {
233    delete fileID;
234  }
235  if (ownerKey) {
236    delete ownerKey;
237  }
238  if (userKey) {
239    delete userKey;
240  }
241}
242
243void *StandardSecurityHandler::makeAuthData(GooString *ownerPassword,
244                                            GooString *userPassword) {
245  return new StandardAuthData(ownerPassword ? ownerPassword->copy()
246                                            : (GooString *)NULL,
247                              userPassword ? userPassword->copy()
248                                           : (GooString *)NULL);
249}
250
251void *StandardSecurityHandler::getAuthData() {
252#if HAVE_XPDFCORE
253  XPDFCore *core;
254  GooString *password;
255
256  if (!(core = (XPDFCore *)doc->getGUIData()) ||
257      !(password = core->getPassword())) {
258    return NULL;
259  }
260  return new StandardAuthData(password, password->copy());
261#elif HAVE_WINPDFCORE
262  WinPDFCore *core;
263  GooString *password;
264
265  if (!(core = (WinPDFCore *)doc->getGUIData()) ||
266      !(password = core->getPassword())) {
267    return NULL;
268  }
269  return new StandardAuthData(password, password->copy());
270#else
271  return NULL;
272#endif
273}
274
275void StandardSecurityHandler::freeAuthData(void *authData) {
276  delete (StandardAuthData *)authData;
277}
278
279GBool StandardSecurityHandler::authorize(void *authData) {
280  GooString *ownerPassword, *userPassword;
281
282  if (!ok) {
283    return gFalse;
284  }
285  if (authData) {
286    ownerPassword = ((StandardAuthData *)authData)->ownerPassword;
287    userPassword = ((StandardAuthData *)authData)->userPassword;
288  } else {
289    ownerPassword = NULL;
290    userPassword = NULL;
291  }
292  if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength,
293                            ownerKey, userKey, permFlags, fileID,
294                            ownerPassword, userPassword, fileKey,
295                            encryptMetadata, &ownerPasswordOk)) {
296    return gFalse;
297  }
298  return gTrue;
299}
300
301#ifdef ENABLE_PLUGINS
302
303//------------------------------------------------------------------------
304// ExternalSecurityHandler
305//------------------------------------------------------------------------
306
307ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA,
308                                                 Object *encryptDictA,
309                                                 XpdfSecurityHandler *xshA):
310  SecurityHandler(docA)
311{
312  encryptDictA->copy(&encryptDict);
313  xsh = xshA;
314  ok = gFalse;
315
316  if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA,
317                      (XpdfObject)encryptDictA, &docData)) {
318    return;
319  }
320
321  ok = gTrue;
322}
323
324ExternalSecurityHandler::~ExternalSecurityHandler() {
325  (*xsh->freeDoc)(xsh->handlerData, docData);
326  encryptDict.free();
327}
328
329void *ExternalSecurityHandler::makeAuthData(GooString *ownerPassword,
330                                            GooString *userPassword) {
331  char *opw, *upw;
332  void *authData;
333
334  opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL;
335  upw = userPassword ? userPassword->getCString() : (char *)NULL;
336  if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) {
337    return NULL;
338  }
339  return authData;
340}
341
342void *ExternalSecurityHandler::getAuthData() {
343  void *authData;
344
345  if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) {
346    return NULL;
347  }
348  return authData;
349}
350
351void ExternalSecurityHandler::freeAuthData(void *authData) {
352  (*xsh->freeAuthData)(xsh->handlerData, docData, authData);
353}
354
355GBool ExternalSecurityHandler::authorize(void *authData) {
356  char *key;
357  int length;
358
359  if (!ok) {
360    return gFalse;
361  }
362  permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData);
363  if (!(permFlags & xpdfPermissionOpen)) {
364    return gFalse;
365  }
366  if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) {
367    return gFalse;
368  }
369  if ((fileKeyLength = length) > 16) {
370    fileKeyLength = 16;
371  }
372  memcpy(fileKey, key, fileKeyLength);
373  (*xsh->freeKey)(xsh->handlerData, docData, key, length);
374  return gTrue;
375}
376
377#endif // ENABLE_PLUGINS
Note: See TracBrowser for help on using the repository browser.