Add new public API FPDF_GetDocUserPermissions
FPDF_GetDocUserPermissions return user access
even if the document is opened with the 'owner password'
Useful for retrieving or editing user permissions of a doc,
even though the document was unlocked using the owner password
Bug: pdfium:2040
Change-Id: I76658d72691e8d6593e89e28a99a3fc4ce2c5637
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/108670
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp
index 8f53f4e..3e7720c 100644
--- a/core/fpdfapi/parser/cpdf_document.cpp
+++ b/core/fpdfapi/parser/cpdf_document.cpp
@@ -399,8 +399,8 @@
return CountPages(std::move(pPages), &visited_pages).value_or(0);
}
-uint32_t CPDF_Document::GetUserPermissions() const {
- return m_pParser ? m_pParser->GetPermissions() : 0;
+uint32_t CPDF_Document::GetUserPermissions(bool get_owner_perms) const {
+ return m_pParser ? m_pParser->GetPermissions(get_owner_perms) : 0;
}
RetainPtr<CPDF_StreamAcc> CPDF_Document::GetFontFileStreamAcc(
diff --git a/core/fpdfapi/parser/cpdf_document.h b/core/fpdfapi/parser/cpdf_document.h
index a261bbc..554831a 100644
--- a/core/fpdfapi/parser/cpdf_document.h
+++ b/core/fpdfapi/parser/cpdf_document.h
@@ -107,7 +107,9 @@
RetainPtr<const CPDF_Dictionary> GetPageDictionary(int iPage);
RetainPtr<CPDF_Dictionary> GetMutablePageDictionary(int iPage);
int GetPageIndex(uint32_t objnum);
- uint32_t GetUserPermissions() const;
+ // When `get_owner_perms` is true, returns full permissions if unlocked by
+ // owner.
+ uint32_t GetUserPermissions(bool get_owner_perms) const;
// PageDataIface wrappers, try to avoid explicit getter calls.
RetainPtr<CPDF_StreamAcc> GetFontFileStreamAcc(
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp
index 098e67e..dd4af5a 100644
--- a/core/fpdfapi/parser/cpdf_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -1069,8 +1069,10 @@
return ToDictionary(m_pSyntax->GetObjectBody(m_pObjectsHolder));
}
-uint32_t CPDF_Parser::GetPermissions() const {
- return m_pSecurityHandler ? m_pSecurityHandler->GetPermissions() : 0xFFFFFFFF;
+uint32_t CPDF_Parser::GetPermissions(bool get_owner_perms) const {
+ return m_pSecurityHandler
+ ? m_pSecurityHandler->GetPermissions(get_owner_perms)
+ : 0xFFFFFFFF;
}
std::unique_ptr<CPDF_LinearizedHeader> CPDF_Parser::ParseLinearizedHeader() {
diff --git a/core/fpdfapi/parser/cpdf_parser.h b/core/fpdfapi/parser/cpdf_parser.h
index 09dc724..ea8409a 100644
--- a/core/fpdfapi/parser/cpdf_parser.h
+++ b/core/fpdfapi/parser/cpdf_parser.h
@@ -87,7 +87,7 @@
FX_FILESIZE GetLastXRefOffset() const { return m_LastXRefOffset; }
- uint32_t GetPermissions() const;
+ uint32_t GetPermissions(bool get_owner_perms) const;
uint32_t GetRootObjNum() const;
uint32_t GetInfoObjNum() const;
RetainPtr<const CPDF_Array> GetIDArray() const;
diff --git a/core/fpdfapi/parser/cpdf_security_handler.cpp b/core/fpdfapi/parser/cpdf_security_handler.cpp
index badb1b5..598e0dc 100644
--- a/core/fpdfapi/parser/cpdf_security_handler.cpp
+++ b/core/fpdfapi/parser/cpdf_security_handler.cpp
@@ -216,8 +216,9 @@
return CheckPassword(password, false);
}
-uint32_t CPDF_SecurityHandler::GetPermissions() const {
- uint32_t dwPermission = m_bOwnerUnlocked ? 0xFFFFFFFF : m_Permissions;
+uint32_t CPDF_SecurityHandler::GetPermissions(bool get_owner_perms) const {
+ uint32_t dwPermission =
+ m_bOwnerUnlocked && get_owner_perms ? 0xFFFFFFFF : m_Permissions;
if (m_pEncryptDict &&
m_pEncryptDict->GetByteStringFor("Filter") == "Standard") {
// See PDF Reference 1.7, page 123, table 3.20.
diff --git a/core/fpdfapi/parser/cpdf_security_handler.h b/core/fpdfapi/parser/cpdf_security_handler.h
index 300dd9b..a53436f 100644
--- a/core/fpdfapi/parser/cpdf_security_handler.h
+++ b/core/fpdfapi/parser/cpdf_security_handler.h
@@ -34,7 +34,9 @@
const CPDF_Array* pIdArray,
const ByteString& user_password);
- uint32_t GetPermissions() const;
+ // When `get_owner_perms` is true, returns full permissions if unlocked by
+ // owner.
+ uint32_t GetPermissions(bool get_owner_perms) const;
bool IsMetadataEncrypted() const;
CPDF_CryptoHandler* GetCryptoHandler() const {
diff --git a/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp b/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp
index cf1a2b5..1475cfd 100644
--- a/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp
+++ b/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp
@@ -108,12 +108,16 @@
TEST_F(CPDFSecurityHandlerEmbedderTest, Unencrypted) {
ASSERT_TRUE(OpenDocument("about_blank.pdf"));
+ // parser is missing a security handler, so always results in 0xFFFFFFFF
EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document()));
+ EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocUserPermissions(document()));
}
TEST_F(CPDFSecurityHandlerEmbedderTest, UnencryptedWithPassword) {
ASSERT_TRUE(OpenDocumentWithPassword("about_blank.pdf", "foobar"));
+ // parser is missing a security handler, so always results in 0xFFFFFFFF
EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document()));
+ EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocUserPermissions(document()));
}
TEST_F(CPDFSecurityHandlerEmbedderTest, NoPassword) {
@@ -127,11 +131,13 @@
TEST_F(CPDFSecurityHandlerEmbedderTest, UserPassword) {
ASSERT_TRUE(OpenDocumentWithPassword("encrypted.pdf", "1234"));
EXPECT_EQ(0xFFFFF2C0, FPDF_GetDocPermissions(document()));
+ EXPECT_EQ(0xFFFFF2C0, FPDF_GetDocUserPermissions(document()));
}
TEST_F(CPDFSecurityHandlerEmbedderTest, OwnerPassword) {
ASSERT_TRUE(OpenDocumentWithPassword("encrypted.pdf", "5678"));
EXPECT_EQ(0xFFFFFFFC, FPDF_GetDocPermissions(document()));
+ EXPECT_EQ(0xFFFFF2C0, FPDF_GetDocUserPermissions(document()));
}
TEST_F(CPDFSecurityHandlerEmbedderTest, PasswordAfterGenerateSave) {
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.cpp b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
index 9aade3a..075e43e 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.cpp
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
@@ -802,7 +802,7 @@
}
bool CPDFSDK_FormFillEnvironment::HasPermissions(uint32_t flags) const {
- return !!(m_pCPDFDoc->GetUserPermissions() & flags);
+ return !!(m_pCPDFDoc->GetUserPermissions(/*get_owner_perms=*/true) & flags);
}
void CPDFSDK_FormFillEnvironment::SendOnFocusChange(
diff --git a/fpdfsdk/cpdfsdk_widget.cpp b/fpdfsdk/cpdfsdk_widget.cpp
index 0b8083e..162502c 100644
--- a/fpdfsdk/cpdfsdk_widget.cpp
+++ b/fpdfsdk/cpdfsdk_widget.cpp
@@ -713,7 +713,8 @@
bool do_hit_test = GetFieldType() == FormFieldType::kPushButton;
if (!do_hit_test) {
- uint32_t perms = GetPDFPage()->GetDocument()->GetUserPermissions();
+ uint32_t perms = GetPDFPage()->GetDocument()->GetUserPermissions(
+ /*get_owner_perms=*/true);
do_hit_test = (perms & pdfium::access_permissions::kFillForm) ||
(perms & pdfium::access_permissions::kModifyAnnotation);
}
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index f93561c..9e7228f 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -368,7 +368,13 @@
FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_GetDocPermissions(FPDF_DOCUMENT document) {
CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
- return pDoc ? pDoc->GetUserPermissions() : 0;
+ return pDoc ? pDoc->GetUserPermissions(/*get_owner_perms=*/true) : 0;
+}
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDF_GetDocUserPermissions(FPDF_DOCUMENT document) {
+ CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+ return pDoc ? pDoc->GetUserPermissions(/*get_owner_perms=*/false) : 0;
}
FPDF_EXPORT int FPDF_CALLCONV
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index bb25225..90f6052 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -486,6 +486,7 @@
CHK(FPDF_GetArrayBufferAllocatorSharedInstance);
#endif
CHK(FPDF_GetDocPermissions);
+ CHK(FPDF_GetDocUserPermissions);
CHK(FPDF_GetFileVersion);
CHK(FPDF_GetLastError);
CHK(FPDF_GetNamedDest);
diff --git a/fpdfsdk/fpdf_view_embeddertest.cpp b/fpdfsdk/fpdf_view_embeddertest.cpp
index d3fb581..be7e15d 100644
--- a/fpdfsdk/fpdf_view_embeddertest.cpp
+++ b/fpdfsdk/fpdf_view_embeddertest.cpp
@@ -484,7 +484,9 @@
EXPECT_TRUE(FPDF_GetFileVersion(document(), &version));
EXPECT_EQ(14, version);
+ // 0xFFFFFFFF because no security handler present
EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document()));
+ EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocUserPermissions(document()));
EXPECT_EQ(-1, FPDF_GetSecurityHandlerRevision(document()));
CloseDocument();
@@ -497,7 +499,9 @@
EXPECT_TRUE(FPDF_GetFileVersion(document(), &version));
EXPECT_EQ(14, version);
+ // 0xFFFFFFFF because no security handler present
EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document()));
+ EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocUserPermissions(document()));
EXPECT_EQ(-1, FPDF_GetSecurityHandlerRevision(document()));
// CloseDocument() called by TearDown().
}
diff --git a/public/fpdfview.h b/public/fpdfview.h
index 0c901a7..c066e6c 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -652,17 +652,29 @@
unsigned int* buffer,
unsigned long length);
-// Function: FPDF_GetDocPermission
+// Function: FPDF_GetDocPermissions
// Get file permission flags of the document.
// Parameters:
// document - Handle to a document. Returned by FPDF_LoadDocument.
// Return value:
// A 32-bit integer indicating permission flags. Please refer to the
// PDF Reference for detailed descriptions. If the document is not
-// protected, 0xffffffff will be returned.
+// protected or was unlocked by the owner, 0xffffffff will be returned.
FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_GetDocPermissions(FPDF_DOCUMENT document);
+// Function: FPDF_GetDocUserPermissions
+// Get user file permission flags of the document.
+// Parameters:
+// document - Handle to a document. Returned by FPDF_LoadDocument.
+// Return value:
+// A 32-bit integer indicating permission flags. Please refer to the
+// PDF Reference for detailed descriptions. If the document is not
+// protected, 0xffffffff will be returned. Always returns user
+// permissions, even if the document was unlocked by the owner.
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDF_GetDocUserPermissions(FPDF_DOCUMENT document);
+
// Function: FPDF_GetSecurityHandlerRevision
// Get the revision for the security handler.
// Parameters: