Encrypting files as a different user

by timvasil 4/28/2009 12:08:00 AM

I'm running a C# application that needs to encrypt/decrypt files (using NTFS's EFS encryption) on behalf of a specific user account--a user account other than the one under which the application is running.  I didn't want to go through the hassle of firing up a new process (using CreateProcessAsUser) because I'd have to worry about IPC and it'd be less performant.  The question I had was:  is it possible to encrypt/decrypt files as a user other than the one under which the process is running within that process?  I couldn't find any resource on the web that stated an answer definitively, so I wrote some code to try it.  The answer is:  yes.

Here are the steps (it involves a mix of Interop and managed methods):

  1. Get a handle to the desired user (the one whose encryption key you want to use) by calling LogonUser.  (You'll need the user's password.)
  2. Load the user's profile (aka registry hive) by calling LoadUserProfile.
  3. Construct a WindowsIdentity object using the handle provided by the call in step 1.
  4. Invoke WindowsIdentity.Impersonate().
  5. Perform any file I/O -- it'll be in the context of that user.  The user's encryption key will be used with any File.Encrypt() / FileInfo.Encrypt() invocation.
  6. Unload the profile by calling UnloadUserProfile.
  7. Close the user handle by calling CloseHandle.

You can do steps 1-4 in the constructor of an IDisposable object and do steps 5-7 in the Dispose() method to ensure proper resource cleanup. 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Windows | .NET Framework | C# | Security

Fixing "Instance names used for writing to custom counters must be 127 characters or less."

by timvasil 11/11/2008 12:39:00 PM

If you've run a unit test in Visual Studio 2008 that utilizes database connectivity, you may have seen this error when creating a connection object:

Instance names used for writing to custom counters must be 127 characters or less.

The problem crops up when you're running the test within a directory structure with a fairly long name, i.e. you're organizing your code well and giving your projects descriptive names.  Well, this error is punishment for being organized.

There are several Microsoft bug reports on the issue.  One has been ignored, the other closed.

There are posts on the web with some workarounds, but none worked for me, perhaps because I'm using Visual Studio 2008?  No matter what I tweaked in .testrunconfig I was still getting the error.  The other approach--shortening the pathname--was really a non-starter.  I wasn't going to compromize well-thought-out organization to get around a Microsoft bug.

So I took a peek at the source of the problem as hinted by the call stack when the error appeared.  It's a method in the internal DbConnectionPoolCounters class in the System.Data.ProviderBase assembly.  Here's the code:

private string GetInstanceName()
{
    string assemblyName = this.GetAssemblyName();
    if (ADP.IsEmpty(assemblyName))
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;
        if (currentDomain != null)
        {
            assemblyName = currentDomain.FriendlyName;
        }
    }
    int currentProcessId = SafeNativeMethods.GetCurrentProcessId();
    return string.Format(null, "{0}[{1}]", new object[] { assemblyName, currentProcessId }).Replace('(', '[').Replace(')', ']').Replace('#', '_').Replace('/', '_').Replace('\\', '_');
}

The instance name of the performance counter is being built, in part, from the name of the AppDomain.  When running tests in Visual Studio, this name can be very, very long, especially if your project's home has a long pathname.

The workaround I pursued, then, is to shorten the name of the app domain.  While AppDomain.FriendlyName is a read-only property, and there's no private field of the AppDomain class to change it, there is a private extern method of AppDomain called nSetupFriendlyName.  And, like magic, if you invoke this method and give the app domain a shorter name, problem solved!

Here's the workaround, utilizing a little reflection magic:

[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
    typeof(AppDomain).GetMethod("nSetupFriendlyName", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(AppDomain.CurrentDomain, new object[] { "Test" });
}

Currently rated 5.0 by 4 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Visual Studio | .NET Framework | C# | ADO.NET | MSTest

Generic type checking and method invocation -- generically!

by timvasil 11/8/2007 5:02:00 PM

Determining whether an object implements the generic version of IDictionary isn't as easy as it seems.  Ideally this would work:

o is IDictionary<,>

Unfortunately, it doesn't.  Leaving out type parameters (i.e. "<,>") is supported only with the typeof operator.

So, after some experimentation, here's how you can do that type of test, and then invoke a generic method with type parameters:

    class Program
    {
        private static readonly MethodInfo _doStuffMethod = typeof(Program).GetMethod("DoStuff");

        static void Main()
        {
            Dictionary<string, int> map = new Dictionary<string, int>();
            Encode(map);
        }

        static void Encode(object val)
        {
            if (val is IEnumerable)
            {
                Type valType = val.GetType();
                if (valType.IsGenericType)
                {
                    foreach (Type valInterface in valType.GetInterfaces())
                    {
                        if (valInterface.IsGenericType && typeof(IDictionary<,>).IsAssignableFrom(valInterface.GetGenericTypeDefinition()))
                        {
                            Type[] valTypeParams = valInterface.GetGenericArguments();
                            _doStuffMethod.MakeGenericMethod(valTypeParams[0], valTypeParams[1]).Invoke(null, new object[] { val });
                        }
                    }
                }
            }
        }

        public static void DoStuff<K, V>(IDictionary<K, V> dic)
        {
            Console.WriteLine(dic.ToString());
        }
    }

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

C#

 

About the author

Tim Vasil Tim Vasil
I'm a software engineer living in Cambridge, MA.

E-mail me Send mail

Search

Calendar

<<  September 2010  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

Recent comments