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