RightsController.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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 IChainOfResponsibiltyNode Members 
    //--------------------------------------------------------------------------
    // 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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK