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

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 10.2 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 "goo/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.