System.UnauthorizedAccessException

The exception that is thrown when the operating system denies access because of an I/O error or a specific type of security error.

Minimum version: >= 1.1 >= Core 1.0

Statistics

12
elmah.io logo 9
6

How to handle it

try
{

}
catch (System.UnauthorizedAccessException e)
{

}
try
{

}
catch (System.UnauthorizedAccessException e) when (e.Message.Contains("something"))
{

}
try
{

}
catch (System.UnauthorizedAccessException e) when (LogException(e))
{

}

private static bool LogException(Exception e)
{
    logger.LogError(...);
    return false;
}

How to avoid it

We haven't written anything about avoiding this exception yet. Got a good tip on how to avoid throwing System.UnauthorizedAccessException? Feel free to reach out through the support widget in the lower right corner with your suggestions.

Links

YouTube videos

Possible fixes from StackOverflow

UPDATE:

Modified the code based on this answer to get rid of obsolete methods.

You can use the Security namespace to check this:

public void ExportToFile(string filename)
{
    var permissionSet = new PermissionSet(PermissionState.None);    
    var writePermission = new FileIOPermission(FileIOPermissionAccess.Write, filename);
    permissionSet.AddPermission(writePermission);

    if (permissionSet.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet))
    {
        using (FileStream fstream = new FileStream(filename, FileMode.Create))
        using (TextWriter writer = new StreamWriter(fstream))
        {
            // try catch block for write permissions 
            writer.WriteLine("sometext");


        }
    }
    else
    {
        //perform some recovery action here
    }

}

As far as getting those permission, you are going to have to ask the user to do that for you somehow. If you could programatically do this, then we would all be in trouble ;)

In UWP apps, you can only access the following files and folders:

If you need access to all files in D:\, the user must manually pick the D:\ drive using the FolderPicker, then you have access to everything in this drive...

UPDATE:

Windows 10 build 17134 (2018 April Update, version 1803) added additional file system access capabilities for UWP apps:

  • Any UWP app (either a regular windowed app or a console app) that declares an AppExecutionAlias is now granted implicit access to the files and folders in the current working directory and downward, when it’s activated from a command line. The current working directory is from whatever file-system location the user chooses to execute your AppExecutionAlias.

  • The new broadFileSystemAccess capability grants apps the same access to the file system as the user who is currently running the app without file-picker style prompts. This access can be set in the manifest in the following manner:

    xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
    ...
    IgnorableNamespaces="uap mp uap5 rescap">
    ...
    <Capabilities>
      <rescap:Capability Name="broadFileSystemAccess" />
    </Capabilities>

These changes and their intention are discussed at length in the MSDN Magazine article titled Universal Windows Platform - Closing UWP-Win32 Gaps. The articles notes the following:

If you declare any restricted capability, this triggers additional scrutiny at the time you submit your package to the Store for publication. ... You don’t need an AppExecutionAlias if you have this capability. Because this is such a powerful feature, Microsoft will grant the capability only if the app developer provides compelling reasons for the request, a description of how this will be used, and an explanation of how this benefits the user.

further:

If you declare the broadFileSystemAccess capability, you don’t need to declare any of the more narrowly scoped file-system capabilities (Documents, Pictures or Videos); indeed, an app must not declare both broadFileSystemAccess and any of the other three file-system capabilities.

finally:

Even after the app has been granted the capability, there’s also a runtime check, because this constitutes a privacy concern for the user. Just like other privacy issues, the app will trigger a user-consent prompt on first use. If the user chooses to deny permission, the app must be resilient to this.

It seems that the problem is that kind of a File.Exists() check is done internally, which fails if the file is hidden (e.g. tries to do a FileMode.Create on a file which already exists).

Therefore, use FileMode.OpenOrCreate to make sure that the file is opened or created even if it is hidden, or just FileMode.Open if you do not want to create it if it doesn't exist.

When FileMode.OpenOrCreate is used though, the file will not be truncated, so you should set its length at the end to make sure that there is no leftover after the end of the text.

using (FileStream fs = new FileStream(filename, FileMode.Open)) {
  using (TextWriter tw = new StreamWriter(fs)) {
    // Write your data here...
    tw.WriteLine("foo");
    // Flush the writer in order to get a correct stream position for truncating
    tw.Flush();
    // Set the stream length to the current position in order to truncate leftover text
    fs.SetLength(fs.Position);
  }
}

If you use .NET 4.5 or later, there is a new overload which prevents the disposal of the StreamWriter to also dispose the underlying stream. The code could then be written slighly more intuitively like this:

using (FileStream fs = new FileStream(filename, FileMode.Open)) {
  using (TextWriter tw = new StreamWriter(fs, Encoding.UTF8, 1024, true)) {
    // Write your data here...
    tw.WriteLine("foo");
  }
  // Set the stream length to the current position in order to truncate leftover text
  fs.SetLength(fs.Position);
}

There are two things which can cause the instantiation of a second or subsequent NamedPipeServerStream on the same pipe to fail:

  • the maxNumberOfServerInstances ctor argument must have been set to more than 1 when the first instance of the pipe server was created. If not, the second call will fail unless the first instance has already been closed completely.
  • the process calling the ctor must have the access right represented by PipeAccessRights.CreateNewInstance. This is a powerful right which the pipe server should guard jealously, as it allows its possessor the ability to act as a pipe server.

The service process should set the pipe security thus:

PipeSecurity ps = new PipeSecurity(); 
    ps.AddAccessRule(new PipeAccessRule(myPipeUsersGroup, PipeAccessRights.ReadWrite, AccessControlType.Allow)); 
    ps.AddAccessRule(new PipeAccessRule(myPipeServerIdentity, PipeAccessRights.FullControl, AccessControlType.Allow)); 

where:

  • myPipeUsersGroup is a placeholder for a group which contains all the prospective client identities which will connect to the pipe. Depending on your requirements/use case this might be a specific client identity, a custom group, or a built in group such as "Users" or "Administrators".
  • myPipeServerIdentity is a placeholder for the service identity. This might be set, for example, to WindowsIdentity.GetCurrent().Owner. When the pipe server is hosted in a Windows service, then even better (but a good deal harder to implement) would be the Logon SID identity of the service process - this would ensure that only the specific service process could create instances of the pipe.

If you want to ensure that pipe access is restricted to just users logged on locally i.e. to prevent remote access across a network, you can also add a deny ACE for Network Users into the pipe security ACL.

I figured it out.

static void Main()
{
    PipeSecurity ps = new PipeSecurity();
    ps.AddAccessRule(new PipeAccessRule("Users", PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));
    ps.AddAccessRule(new PipeAccessRule("CREATOR OWNER", PipeAccessRights.FullControl, AccessControlType.Allow));
    ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow));
    ps.AddAccessRule(pa);
    using (NamedPipeServerStream pipeServer =
        new NamedPipeServerStream("testpipe",PipeDirection.InOut,10, 
                                    PipeTransmissionMode.Message, PipeOptions.WriteThrough, 1024,1024,ps))
    using (NamedPipeServerStream pipeServer2 =
        new NamedPipeServerStream("testpipe", PipeDirection.InOut, 10,
                                    PipeTransmissionMode.Message, PipeOptions.WriteThrough,1024,1024,ps))
    {

By adding the rights PipeAccessRights.CreateNewInstance it now works fine.


I hit another snag but i solved it, but wanted to post it in case other people found this through Google. by providing your own Pipe security object it removes the default one, so if you need it you need to re-add the System group so it can talk to the pipe if you are writing a service. I updated my above code to what I used to get a elevated service and a non elevated winforms app to talk to each other (Creator owner is likely unnecessary)