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: