Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / TrustUi / MS / Internal / documents / Application / RightsController.cs / 1 / RightsController.cs
//------------------------------------------------------------------------------ //// Copyright (C) Microsoft Corporation. All rights reserved. // //// Responsible for the lifecycle of the RightsDocument and the actions that can // be performed on it. // // // History: // 08/28/2005: [....]: Initial implementation. //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.IO; using System.IO.Packaging; using System.Security; using System.Security.Permissions; using System.Security.RightsManagement; using System.Windows; using System.Windows.TrustUI; // for SR using MS.Internal.IO.Packaging.CompoundFile; using MS.Internal.Permissions; using MS.Internal.WindowsBase; // for SecurityHelper namespace MS.Internal.Documents.Application { ////// Responsible for the lifecycle of the RightsDocument and the actions that can /// be performed on it. /// ////// /// All IDocumentController methods are expected to throw if provided /// a document that is not a RightsDocument. Users of the IDocumentController /// interface are expected to use the IChainOfResponsibiltyNode method before /// calling into the IDocumentController methods to avoid runtime errors. /// class RightsController : IDocumentController, IDisposable { #region IDocumentController Members //------------------------------------------------------------------------- // IDocumentController Members //------------------------------------------------------------------------- ////// ////// /// Critical: /// 1) calls critical function DecryptEnvelopeAndSuppressStream /// 2) sets WorkspaceProxy and WorkspacePackage /// TreatAsSafe: /// 1) encrypted package envelope comes indirectly from the stream based /// on a critical dependency (safe value) /// 2) these are both set from the same critical dependency /// [SecurityCritical, SecurityTreatAsSafe] bool IDocumentController.EnableEdit(Document document) { RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok Stream ciphered = doc.Dependency.Workspace; Stream clear = ciphered; bool canEdit = DocumentRightsManagementManager.Current.HasPermissionToEdit; EncryptedPackageEnvelope encryptedPackage = null; // If editing the document is allowed (i.e. the document is either // not RM protected, or the user has permission to edit it), create // a temporary editing file if (canEdit) { try { encryptedPackage = _provider.Value.EncryptPackage(ciphered); if (encryptedPackage != null) { clear = DecryptEnvelopeAndSuppressStream( encryptedPackage, canEdit); doc.WorkspacePackage = encryptedPackage; } } catch (RightsManagementException exception) { RightsManagementErrorHandler.HandleOrRethrowException( RightsManagementOperation.Other, exception); // Bail out return true; } if (encryptedPackage != null) { Trace.SafeWrite( Trace.Rights, "Editing package is RM protected."); } else { Trace.SafeWrite( Trace.Rights, "Editing package is unprotected."); } doc.WorkspaceProxy = new StreamProxy(clear); } else { Trace.SafeWrite( Trace.Rights, "Did not create editing package because user does not have permission to edit."); } return canEdit; } ////// ////// /// Critical: /// 1) calls critical function OpenEnvelopeOnStream /// 2) sets SourcePackage /// 3) sets RM provider and initializes RM manager /// 4) uses critical constructor of RightsManagementSuppressedStream /// 5) sets SourceProxy /// 6) we construct SuppressedProperties /// TreatAsSafe: /// 1) stream for envelope is from a critical dependency (safe value) /// 2) source package comes from the same critical dependency /// 3) by definition, we are responsible for initializing RM, and we do so /// from the critical for set SourcePackage that we just opened /// 4) suppressed stream is created on a stream that comes from the same /// critical dependency /// 5) source proxy is also set from the same dependency /// 6) EncryptedPackage (which require RightsManagementPermission) is the /// only type for the SuppressProperties ctor; this is safe because this /// is the correct source for the data /// [SecurityCritical, SecurityTreatAsSafe] bool IDocumentController.Open(Document document) { RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok Stream ciphered = doc.Dependency.Source; Stream clear = ciphered; bool isSourceProtected = doc.IsSourceProtected(); if (isSourceProtected) { // Do not catch exceptions here - there can be no mitigation EncryptedPackageEnvelope envelope = OpenEnvelopeOnStream(ciphered); PackageProperties properties = new SuppressedProperties(envelope); doc.SourcePackage = envelope; DocumentProperties.Current.SetRightsManagedProperties(properties); } RightsManagementProvider provider = new RightsManagementProvider(doc.SourcePackage); _provider.Value = provider; try { DocumentRightsManagementManager.Initialize(provider); DocumentRightsManagementManager.Current.PublishLicenseChange += new EventHandler(delegate(object sender, EventArgs args) { Trace.SafeWrite( Trace.Rights, "Disabling file copy for current document."); doc.IsFileCopySafe = false; DocumentManager.CreateDefault().EnableEdit(null); }); if (isSourceProtected) { clear = DocumentRightsManagementManager.Current.DecryptPackage(); if (clear != null) { clear = new RightsManagementSuppressedStream( clear, DocumentRightsManagementManager.Current.HasPermissionToEdit); // Reset the position of the stream since GetPackageStream will // create a package and move the stream pointer somewhere else clear.Position = 0; } else { Trace.SafeWrite( Trace.Rights, "You do not have rights for the current document."); return false; } } } catch { // If anything failed here, we cannot use the provider any longer, // so we can dispose it provider.Dispose(); _provider.Value = null; throw; } if (clear != null) { doc.SourceProxy = new StreamProxy(clear); } else { // If decryption failed, we can no longer do anything with the // provider instance or the current RM manager provider.Dispose(); _provider.Value = null; } return true; } ////// ////// /// Critical: /// 1) calls critical function CloseEnvelope /// 2) calls critical function OpenEnvelopeOnStream /// 3) sets SourcePackage /// 4) calls DocumentRightsManagementManager.SetEncryptedPackage /// 5) uses critical constructor of RightsManagementSuppressedStream /// 6) sets SourceProxy /// 7) we construct SuppressedProperties /// TreatAsSafe: /// 1) envelope passed in is critical for set /// 2) data into critical function is based on critical dependency (safe /// value) /// 3) source package comes from the same critical dependency /// 4) by definition, we are responsible for opening rights managed files /// 5) suppressed stream is created on a stream that comes from the same /// critical dependency /// 6) source proxy is set from the suppressed stream whose creation is /// safe as in #5 /// 7) EncryptedPackage (which require RightsManagementPermission) is the /// only type for the SuppressProperties ctor; this is safe because this /// is the correct source for the data /// [SecurityCritical, SecurityTreatAsSafe] bool IDocumentController.Rebind(Document document) { RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok Stream ciphered = doc.Dependency.Source; Stream clear = ciphered; if (doc.IsRebindNeeded) { if (doc.SourcePackage != null) { CloseEnvelope(doc.SourcePackage); doc.SourcePackage = null; } EncryptedPackageEnvelope envelope = null; PackageProperties properties = null; bool isSourceProtected = doc.IsSourceProtected(); if (isSourceProtected) { envelope = OpenEnvelopeOnStream(ciphered); doc.SourcePackage = envelope; properties = new SuppressedProperties(envelope); } DocumentProperties.Current.SetRightsManagedProperties(properties); DocumentRightsManagementManager.Current.SetEncryptedPackage(envelope); if (isSourceProtected) { clear = DocumentRightsManagementManager.Current.DecryptPackage(); if (clear != null) { clear = new RightsManagementSuppressedStream( clear, DocumentRightsManagementManager.Current.HasPermissionToEdit); // Reset the position of the stream since GetPackageStream will // create a package and move the stream pointer somewhere else clear.Position = 0; } else { Trace.SafeWrite( Trace.Rights, "You do not have rights for the current document."); return false; } } doc.SourceProxy.Target = clear; } return true; } ////// bool IDocumentController.SaveAsPreperation(Document document) { if (!DocumentRightsManagementManager.Current.HasPermissionToSave) { Trace.SafeWrite(Trace.Rights, "Can not save a package when we do not have permission."); return false; } return ((IDocumentController)this).SavePreperation(document); } ////// /// ////// /// Critical /// 1) calls critical function CloseEnvelope /// TreatAsSafe /// 1) envelope passed in is critical for set /// [SecurityCritical, SecurityTreatAsSafe] bool IDocumentController.SaveCommit(Document document) { RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok if (doc.DestinationPackage != null) { CloseEnvelope(doc.DestinationPackage); doc.DestinationPackage = null; Trace.SafeWrite(Trace.File, "Destination EncryptedPackageEnvelope closed."); } return true; } ////// ////// /// Critical: /// 1) calls critical functions OpenEnvelopeOnStream and /// DecryptEnvelopeAndSuppressStream /// 2) asserts for RightsManagementPermission to copy the CryptoProvider /// from the source to the destination EncryptedPackageEnvelope /// 3) sets DestinationProxy /// 4) calls critical function SaveUseLicense to save the use license back /// to the encrypted package envelope /// TreatAsSafe: /// 1) envelope stream always comes from a critical dependency (safe /// value), and the decision whether or not to perform this action /// comes from critical for set IsDestinationIdenticalToSource /// 2) the CryptoProvider comes from the critical for set source package /// 3) new DestinationProxy comes from the same critical dependency /// 4) the data passed to SaveUseLicense (doc.DestinationPackage) is /// critical for set /// [SecurityCritical, SecurityTreatAsSafe] bool IDocumentController.SavePreperation(Document document) { bool handled = false; RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok Stream ciphered = doc.Dependency.Destination; Stream clear = ciphered; // We protect the actual decrypted content (if necessary) using the // RightsManagementSuppressedStream that prevents callers from writing // to it. This still allows us to save an acquired use license back to // the package even if the user does not have the permissions to modify // the document itself. It also means that there is no need to check if // the user has permission to save before starting the operation. // If we are encrypted and the destination stream is identical to the // source stream, there is no need to create a new envelope. Instead we // can simply open the envelope on the destination stream, which // already contains the complete encrypted envelope that was the source // file. // // It doesn't actually matter to this class why the flag was set, but // we know the destination is identical to the source in two situations: // 1) The source and the destination are the same file, and since the // publish license didn't change there is no need to write to a // temporary file first // 2) The destination file was copied directly from the source file. if (doc.IsDestinationProtected() && doc.IsDestinationIdenticalToSource) { // we can't reuse protections because EncryptedPackage caches the // original permissions for the stream (if we re-open the package r/w // the Encrypted package will still be r/o) doc.DestinationPackage = OpenEnvelopeOnStream( doc.Dependency.Destination); (new RightsManagementPermission()).Assert(); //BlessedAssert try { doc.DestinationPackage.RightsManagementInformation.CryptoProvider = doc.SourcePackage.RightsManagementInformation.CryptoProvider; } finally { RightsManagementPermission.RevertAssert(); } clear = DecryptEnvelopeAndSuppressStream( doc.DestinationPackage, DocumentRightsManagementManager.Current.HasPermissionToEdit); doc.DestinationProxy = new StreamProxy(clear); // save the use license in case the user acquired one _provider.Value.SaveUseLicense(doc.DestinationPackage); handled = true; Trace.SafeWrite( Trace.Rights, "Reused CryptoProvider as underlying stream is the same."); } else // we are not protected and/or the RM protections have changed { bool canEdit = DocumentRightsManagementManager.Current.HasPermissionToEdit; // canEdit should always be true here - either the document is not // protected, or the protections have been changed. In the latter // case, the user has to have Owner permissions to change the // protections, and that of course includes Edit permissions. Invariant.Assert( canEdit, "Cannot save with changes if Edit permission was not granted."); EncryptedPackageEnvelope encryptedPackage = _provider.Value.EncryptPackage(ciphered); // the destination is intended to be encrypted when a non-null // value is returned if (encryptedPackage != null) { clear = DecryptEnvelopeAndSuppressStream( encryptedPackage, canEdit); doc.DestinationPackage = encryptedPackage; } Trace.SafeWriteIf( encryptedPackage == null, Trace.Rights, "Destination package is unprotected."); doc.DestinationProxy = new StreamProxy(clear); // If the destination file is not identical to the source file, we // need to copy the (possibly decrypted) source stream to the // destination here. if (!doc.IsDestinationIdenticalToSource) { StreamHelper.CopyStream(doc.Source, doc.Destination); doc.DestinationProxy.Flush(); Trace.SafeWrite( Trace.Rights, "Copied Source contents to Destination."); } handled = true; } return handled; } #endregion IDocumentController Members #region IChainOfResponsibiltyNodeMembers //-------------------------------------------------------------------------- // IChainOfResponsibiltyNode Members //------------------------------------------------------------------------- /// /// bool IChainOfResponsibiltyNode/// .IsResponsible(Document subject) { return subject is RightsDocument; } #endregion IChainOfResponsibiltyNode Members #region IDisposable Members //-------------------------------------------------------------------------- // IDisposable Members //-------------------------------------------------------------------------- /// /// Dispose /// ////// Critical /// - sets critical data for set _provider /// TreatAsSafe /// - sets _provider to known safe value null /// [SecurityCritical, SecurityTreatAsSafe] void IDisposable.Dispose() { IDisposable provider = _provider.Value as IDisposable; if (provider != null) { provider.Dispose(); } _provider.Value = null; } #endregion IDisposable Members #region Private Methods //------------------------------------------------------------------------- // Private Methods //-------------------------------------------------------------------------- ////// Opens an EncryptedPackageEnvelope on a given stream. /// /// The encrypted stream ///An EncryptedPackageEnvelope on the stream ////// This function exists to centralize the asserts needed to use encrypted /// package envelopes. /// ////// Critical /// 1) Asserts for CompoundFileIOPermission to open an envelope on the stream /// [SecurityCritical] private static EncryptedPackageEnvelope OpenEnvelopeOnStream(Stream ciphered) { _compoundFileIOPermission.Assert(); //BlessedAssert try { return EncryptedPackageEnvelope.Open(ciphered); } finally { CompoundFileIOPermission.RevertAssert(); } } ////// Retrieves and creates a rights management suppressed stream around the /// decrypted stream from a given encrypted package envelope. The stream /// returned should not be handed out to untrusted code. /// /// The envelope to decrypt and suppress /// True if editing the suppressed stream should /// be allowed ///The new demand-suppressed stream ////// This function exists to centralize the asserts needed to use encrypted /// package envelopes. /// ////// Critical /// 1) Asserts for EnvelopePermissionSet to get the decrypted stream /// 2) Creates a RightsManagementSuppressedStream around the decrypted /// stream, which is a critical operation /// [SecurityCritical] private static Stream DecryptEnvelopeAndSuppressStream( EncryptedPackageEnvelope envelope, bool allowWrite) { Stream clear = null; SecurityHelper.EnvelopePermissionSet.Assert(); // BlessedAssert try { clear = envelope.GetPackageStream(); } finally { CodeAccessPermission.RevertAll(); } clear = new RightsManagementSuppressedStream(clear, allowWrite); // Reset the position of the stream since GetPackageStream will // create a package and move the stream pointer somewhere else clear.Position = 0; return clear; } ////// Close the EncryptedPackageEnvelope passed in as an argument. /// /// The envelope to close ////// This function exists to centralize the asserts needed to use encrypted /// package envelopes. /// ////// Critical /// 1) Asserts for EnvelopePermissionSet to close the envelope /// [SecurityCritical] private static void CloseEnvelope(EncryptedPackageEnvelope envelope) { _compoundFileIOPermission.Assert(); // BlessedAssert try { envelope.Close(); } finally { CompoundFileIOPermission.RevertAssert(); } } #endregion Private Methods #region Private Fields //------------------------------------------------------------------------- // Private Fields //------------------------------------------------------------------------- ////// Critical /// 1) Creation of the permission is critical as the code will be /// asserting for it and we do not want it replaced without review. /// TreatAsSafe /// 1) Future reviewers, this value should only ever represent /// CompoundFileIOPermission. It should not be changed without /// reviewing all uses of it in the class. (This is safe because it's /// being reviewed.) /// [SecurityCritical, SecurityTreatAsSafe] private static CompoundFileIOPermission _compoundFileIOPermission = new CompoundFileIOPermission(); ////// Critical: /// - swapping out for a provider that has a weaker publish license would /// result in information disclosure /// - swaping out for a malicious provider could yield a man in the middle /// attack /// private static SecurityCriticalDataForSet_provider; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- AccessText.cs
- ServicePointManager.cs
- ColumnHeader.cs
- HotCommands.cs
- CodeCommentStatement.cs
- BaseAsyncResult.cs
- CompositeDuplexElement.cs
- HandlerMappingMemo.cs
- ADMembershipUser.cs
- XhtmlBasicLinkAdapter.cs
- Transform3DGroup.cs
- ServiceNameElement.cs
- DataBoundControlHelper.cs
- ProviderMetadataCachedInformation.cs
- WindowsFormsEditorServiceHelper.cs
- NameTable.cs
- TransactedBatchContext.cs
- GridLengthConverter.cs
- WindowsToolbar.cs
- StringKeyFrameCollection.cs
- SafeRightsManagementSessionHandle.cs
- Attributes.cs
- Win32Exception.cs
- DictionarySectionHandler.cs
- CodeTypeDeclarationCollection.cs
- SqlError.cs
- ManagementException.cs
- ImmutableAssemblyCacheEntry.cs
- ClientScriptManagerWrapper.cs
- RuntimeHandles.cs
- ListManagerBindingsCollection.cs
- TypeConstant.cs
- ResolveDuplex11AsyncResult.cs
- RangeBase.cs
- AssociationProvider.cs
- DeclarativeCatalogPartDesigner.cs
- ReadOnlyDictionary.cs
- prompt.cs
- PasswordDeriveBytes.cs
- WaitHandleCannotBeOpenedException.cs
- BigInt.cs
- Path.cs
- Rijndael.cs
- IWorkflowDebuggerService.cs
- CheckBoxRenderer.cs
- ModelPropertyDescriptor.cs
- MenuItemBinding.cs
- SqlClientWrapperSmiStreamChars.cs
- ScriptIgnoreAttribute.cs
- IpcChannelHelper.cs
- ProxyHwnd.cs
- EntitySetDataBindingList.cs
- FontNameConverter.cs
- BaseCodePageEncoding.cs
- TagMapInfo.cs
- TypedTableBaseExtensions.cs
- DataGridColumnHeadersPresenterAutomationPeer.cs
- InputElement.cs
- Odbc32.cs
- GatewayDefinition.cs
- DataGridViewHitTestInfo.cs
- HttpApplicationFactory.cs
- HyperLinkDesigner.cs
- FixedHighlight.cs
- PriorityItem.cs
- DrawingContext.cs
- KnowledgeBase.cs
- IndependentlyAnimatedPropertyMetadata.cs
- RijndaelManagedTransform.cs
- Wildcard.cs
- StrongNameIdentityPermission.cs
- SQLInt64.cs
- CallbackValidator.cs
- ListBase.cs
- TrackingServices.cs
- DeviceFiltersSection.cs
- TreeNodeCollection.cs
- Clock.cs
- ConfigXmlSignificantWhitespace.cs
- KeyboardNavigation.cs
- WindowsRichEdit.cs
- DocumentViewerBaseAutomationPeer.cs
- XsltException.cs
- AppSettingsSection.cs
- TransformPatternIdentifiers.cs
- PageThemeCodeDomTreeGenerator.cs
- TextMetrics.cs
- recordstatefactory.cs
- EpmSyndicationContentSerializer.cs
- SpeechSynthesizer.cs
- ResizingMessageFilter.cs
- ExtensionDataObject.cs
- DataGridAddNewRow.cs
- SchemaLookupTable.cs
- MetadataArtifactLoaderResource.cs
- autovalidator.cs
- ChangeTracker.cs
- MessagePartDescriptionCollection.cs
- CodeTryCatchFinallyStatement.cs
- AttachedPropertyMethodSelector.cs