Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
FileSystemSecurity.cs345 linesDownload Raw Back to namespaces
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.IO;6using System.Management.Automation;7using System.Management.Automation.Internal;8using System.Management.Automation.Provider;9using System.Security.AccessControl;10 11namespace Microsoft.PowerShell.Commands12{13    /// <summary>14    /// The FileSystemProvider provides stateless namespace navigation15    /// of the file system.16    /// </summary>17    public sealed partial class FileSystemProvider : NavigationCmdletProvider, IContentCmdletProvider, IPropertyCmdletProvider, ISecurityDescriptorCmdletProvider18    {19        #region ISecurityDescriptorCmdletProvider members20 21        /// <summary>22        /// Gets the SecurityDescriptor at the specified path, including only the specified23        /// AccessControlSections.24        /// </summary>25        /// <param name="path">26        /// The path of the item to retrieve. It may be a drive or provider-qualified path and may include.27        /// glob characters.28        /// </param>29        /// <param name="sections">30        /// The sections of the security descriptor to include.31        /// </param>32        /// <returns>33        /// Nothing. An object that represents the security descriptor for the item34        /// specified by path is written to the context's pipeline.35        /// </returns>36        /// <exception cref="System.ArgumentException">37        ///     path is null or empty.38        ///     path doesn't exist39        ///     sections is not valid.40        /// </exception>41        public void GetSecurityDescriptor(string path,42                                          AccessControlSections sections)43        {44            ObjectSecurity sd = null;45            path = NormalizePath(path);46 47            if (string.IsNullOrEmpty(path))48            {49                throw PSTraceSource.NewArgumentNullException(nameof(path));50            }51 52            if ((sections & ~AccessControlSections.All) != 0)53            {54                throw PSTraceSource.NewArgumentException(nameof(sections));55            }56 57            var currentPrivilegeState = new PlatformInvokes.TOKEN_PRIVILEGE();58            try59            {60                PlatformInvokes.EnableTokenPrivilege("SeBackupPrivilege", ref currentPrivilegeState);61 62                if (Directory.Exists(path))63                {64                    sd = new DirectorySecurity(path, sections);65                }66                else67                {68                    sd = new FileSecurity(path, sections);69                }70            }71            catch (System.Security.SecurityException e)72            {73                WriteError(new ErrorRecord(e, e.GetType().FullName, ErrorCategory.PermissionDenied, path));74            }75            finally76            {77                PlatformInvokes.RestoreTokenPrivilege("SeBackupPrivilege", ref currentPrivilegeState);78            }79 80            WriteSecurityDescriptorObject(sd, path);81        }82 83        /// <summary>84        /// Sets the SecurityDescriptor at the specified path.85        /// </summary>86        /// <param name="path">87        /// The path of the item to set the security descriptor on.88        /// It may be a drive or provider-qualified path and may include.89        /// glob characters.90        /// </param>91        /// <param name="securityDescriptor">92        /// The new security descriptor for the item.93        /// </param>94        /// <exception cref="System.ArgumentException">95        ///     path is null or empty.96        /// </exception>97        /// <exception cref="System.ArgumentNullException">98        ///     securitydescriptor is null.99        /// </exception>100        public void SetSecurityDescriptor(101            string path,102            ObjectSecurity securityDescriptor)103        {104            if (string.IsNullOrEmpty(path))105            {106                throw PSTraceSource.NewArgumentException(nameof(path));107            }108 109            path = NormalizePath(path);110 111            if (securityDescriptor == null)112            {113                throw PSTraceSource.NewArgumentNullException(nameof(securityDescriptor));114            }115 116            if (!File.Exists(path) && !Directory.Exists(path))117            {118                ThrowTerminatingError(CreateErrorRecord(path,119                                                        "SetSecurityDescriptor_FileNotFound"));120            }121 122            FileSystemSecurity sd = securityDescriptor as FileSystemSecurity;123 124            if (sd == null)125            {126                throw PSTraceSource.NewArgumentException(nameof(securityDescriptor));127            }128            else129            {130                // This algorithm works around the following security descriptor complexities:131                //132                //     - In order to copy an ACL between files, you need to use the133                //       binary form, and transfer all sections. If you don't use the binary form,134                //       then the FileSystem only applies changes that have happened to that specific135                //       ACL object -- which will not be present if you are just stamping a specific136                //       ACL on a lot of files.137                //     - Copying a full ACL means copying its Audit section, which normal users138                //       don't have access to.139                //140                // In order to make this cmdlet support regular users modifying their own files,141                // the solution is to:142                //143                //     - First attempt to copy the entire security descriptor as we did in V1.144                //       This ensures backward compatibility for administrator scripts that currently145                //       work.146                //     - If the attempt fails due to a PrivilegeNotHeld exception, try again with147                //       an estimate of the minimum required subset. This is an estimate, since the148                //       ACL object doesn't tell you exactly what's changed.149                //           - If their ACL doesn't include any audit rules, don't try to set the150                //             audit section. If it does contain Audit rules, continue to try and151                //             set the section, so they get an appropriate error message.152                //           - If their ACL has the same Owner / Group as the destination file,153                //             also don't try to set those sections.154                //       If they added audit rules, or made changes to the Owner / Group, they will155                //       still get an error message.156                //157                // We can't roll the two steps into one, as the second step can't handle the158                // situation where an admin wants to _clear_ the audit entries. It would be nice to159                // detect a difference in audit entries (like we do with Owner and Group,) but160                // retrieving the Audit entries requires SeSecurityPrivilege as well.161 162                try163                {164                    // Try to set the entire security descriptor165                    SetSecurityDescriptor(path, sd, AccessControlSections.All);166                }167                catch (PrivilegeNotHeldException)168                {169                    // Get the security descriptor of the destination path170                    ObjectSecurity existingDescriptor = new FileInfo(path).GetAccessControl();171                    // Use SecurityIdentifier to avoid having the below comparison steps172                    // fail when dealing with an untranslatable SID in the SD173                    Type identityType = typeof(System.Security.Principal.SecurityIdentifier);174 175                    AccessControlSections sections = AccessControlSections.All;176 177                    // If they didn't modify any audit information, don't try to set178                    // the audit section.179                    int auditRuleCount = sd.GetAuditRules(true, true, identityType).Count;180                    if ((auditRuleCount == 0) &&181                        (sd.AreAuditRulesProtected == existingDescriptor.AreAccessRulesProtected))182                    {183                        sections &= ~AccessControlSections.Audit;184                    }185 186                    // If they didn't modify the owner, don't try to set that section.187                    if (sd.GetOwner(identityType) == existingDescriptor.GetOwner(identityType))188                    {189                        sections &= ~AccessControlSections.Owner;190                    }191 192                    // If they didn't modify the group, don't try to set that section.193                    if (sd.GetGroup(identityType) == existingDescriptor.GetGroup(identityType))194                    {195                        sections &= ~AccessControlSections.Group;196                    }197 198                    // Try to set the security descriptor again, this time with a reduced set199                    // of sections.200                    SetSecurityDescriptor(path, sd, sections);201                }202            }203        }204 205        private void SetSecurityDescriptor(string path, ObjectSecurity sd, AccessControlSections sections)206        {207            var currentPrivilegeState = new PlatformInvokes.TOKEN_PRIVILEGE();208            byte[] securityDescriptorBinary = null;209 210            try211            {212                // Get the binary form of the descriptor.213                PlatformInvokes.EnableTokenPrivilege("SeBackupPrivilege", ref currentPrivilegeState);214                securityDescriptorBinary = sd.GetSecurityDescriptorBinaryForm();215            }216            finally217            {218                PlatformInvokes.RestoreTokenPrivilege("SeBackupPrivilege", ref currentPrivilegeState);219            }220 221            try222            {223                PlatformInvokes.EnableTokenPrivilege("SeRestorePrivilege", ref currentPrivilegeState);224 225                // Transfer it to the new file / directory.226                // We keep these two code branches so that we can have more227                // granular information when we output the object type via228                // WriteSecurityDescriptorObject.229                if (Directory.Exists(path))230                {231                    DirectorySecurity newDescriptor = new DirectorySecurity();232                    newDescriptor.SetSecurityDescriptorBinaryForm(securityDescriptorBinary, sections);233                    new DirectoryInfo(path).SetAccessControl(newDescriptor);234                    WriteSecurityDescriptorObject(newDescriptor, path);235                }236                else237                {238                    FileSecurity newDescriptor = new FileSecurity();239                    newDescriptor.SetSecurityDescriptorBinaryForm(securityDescriptorBinary, sections);240                    new FileInfo(path).SetAccessControl(newDescriptor);241                    WriteSecurityDescriptorObject(newDescriptor, path);242                }243            }244            finally245            {246                PlatformInvokes.RestoreTokenPrivilege("SeRestorePrivilege", ref currentPrivilegeState);247            }248        }249 250        /// <summary>251        /// Creates a new empty security descriptor of the same type as252        /// the item specified by the path.  If "path" points to a file system directory,253        /// then the descriptor returned will be of type DirectorySecurity.254        /// </summary>255        /// <param name="path">256        /// Path of the item to use to determine the type of resulting257        /// SecurityDescriptor.258        /// </param>259        /// <param name="sections">260        /// The sections of the security descriptor to create.261        /// </param>262        /// <returns>263        /// A new ObjectSecurity object of the same type as264        /// the item specified by the path.265        /// </returns>266        public ObjectSecurity NewSecurityDescriptorFromPath(267            string path,268            AccessControlSections sections)269        {270            ItemType itemType = ItemType.Unknown;271 272            if (IsItemContainer(path))273            {274                itemType = ItemType.Directory;275            }276            else277            {278                itemType = ItemType.File;279            }280 281            return NewSecurityDescriptor(itemType);282        }283 284        /// <summary>285        /// Creates a new empty security descriptor of the specified type.286        /// </summary>287        /// <param name="type">288        /// The type of Security Descriptor to create. Valid types are289        /// "file", "directory," and "container."290        /// </param>291        /// <param name="sections">292        /// The sections of the security descriptor to create.293        /// </param>294        /// <returns>295        /// A new ObjectSecurity object of the specified type.296        /// </returns>297        public ObjectSecurity NewSecurityDescriptorOfType(298            string type,299            AccessControlSections sections)300        {301            ItemType itemType = ItemType.Unknown;302 303            itemType = GetItemType(type);304            return NewSecurityDescriptor(itemType);305        }306 307        private static ObjectSecurity NewSecurityDescriptor(308            ItemType itemType)309        {310            ObjectSecurity sd = null;311 312            switch (itemType)313            {314                case ItemType.File:315                    sd = new FileSecurity();316                    break;317 318                case ItemType.Directory:319                    sd = new DirectorySecurity();320                    break;321            }322 323            return sd;324        }325 326        private static ErrorRecord CreateErrorRecord(string path,327                                                     string errorId)328        {329            string message = null;330 331            message = StringUtil.Format(FileSystemProviderStrings.FileNotFound, path);332 333            ErrorRecord er =334                new ErrorRecord(new FileNotFoundException(message),335                                errorId,336                                ErrorCategory.ObjectNotFound,337                                null);338 339            return er;340        }341 342        #endregion ISecurityDescriptorCmdletProvider members343    }344}345