Code Mortem

"Old code never dies...you have to kill it." - Grady Booch

Monday, January 30, 2006

Sparkling Fun

http://www.sparkfun.com/

Tinkering with electronics is one of those things that I love to do, but never have time. Someday, I'd love to get some of the items on this site and play around. They have GPS modules, cellular modems, LCDs, gyros, accelerometers, ultrasonics, microcontrollers, you name it...

Tuesday, January 10, 2006

Google Video Trashing

The hype leading up to the Google CES announcement was so thick that they could never have lived up to it of course. What is a surprise to me is how upset many bloggers are about Google Video. Here are a couple of examples: We Sat Around Waiting For Google Video And All We Got Was This?, After the keynote hype, is Google Video worth all the fuss?. I might be only one, but I think Google's take on video is refreshing. Everyone keeps talking about the fact that they created their own DRM, but it's nothing more than a login. Give it up, people! How many people really think that video producers are going to give all this content away for free so it can be spread around the illegal file-sharing networks? A login is something that pretty much everyone who uses the Internet understands and is probably comfortable with. Since the login is stored at the Google site, you can move the video from machine to machine without a problem. If you lose the video when your computer crashes, you just download another copy. That's more than you can say for most other DRM schemes.

Their open approach to selling content is refreshing as well. iTunes doesn't allow just anyone to upload video or audio and sell it online. By opening the publishing mechanism wide open, they are providing a new business opportunity for lots of small-time video producers. If anything, the networks have to be scared to death of this. If you think about what the Internet did to publishing, by allowing blogs to flourish, this could do the same thing for independent video production.

So, I might be the only one, but I love Google Video. I think it's brilliant.

Monday, January 09, 2006

Drifting Into Envy

This is great video of some expensive cars getting thrashed by professional drivers (plus I wanted to test the new Google video posting features). It's a good thing I can't afford one of these cars, this would get me sold in a minute.


Saturday, January 07, 2006

Creating a Null DACL in Managed Code

While the .NET 2.0 framework libraries bring a lot of added value to the original libraries, the documentation at this point leaves a great deal to be desired. One of the challenges that I faced recently was how to create a null DACL for some interop code. The new framework library includes some great classes for setting security on Registry keys, files and synchronization objects, but if you try to go beyond that, watch out. The documentation will provide you no help. I figured this out by spending several hours experimenting with the and by using Reflector to look at the IL inside the Microsoft binaries.

I was trying to create a named pipe in managed code. I'm still surprised that the managed libraries have no support for this yet, but be that as it may, I created the obligatory P/Invoke definition for CreateNamedPipe and called it from my code. That worked fine, but I discovered that the default privileges assigned to the pipe were not adequate so I needed to open up access to my pipe. A DACL is a Discretionary Access Control List in Windows. It is a list of ACE (Access Control Entries) that grant or deny access for a group of users to the associated resource. Every file in Windows (on NTFS) has such a list as do most kernel objects. A null DACL is basically a blank check. If your resource has a null DACL, then everyone has complete access to the resource. Sometimes this is referred to as an AEFA (Allow Everyone Full Access) ACE. This is not the same as an empty DACL; in fact it is the opposite. An empty DACL denies everyone any access to the resource.

Now, I must insert a disclaimer. Somebody will surely respond that I shouldn't be creating a null DACL, because it is insecure. That is not the point of this post. I had a good reason to need open access to my pipe, and I am assuming that anyone wanting to use this technique would as well. This technique is expandable beyond NULL DACL's anyway.

So, let's move on. There are two challenges. One, is that we need to figure out how to create the null DACL using the framework libraries in managed code, and second, we need to figure out how to marshal the information successfully over into the unmanaged API. Here is the P/Invoke declaration for CreateNamedPipe.

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateNamedPipe(string lpName, uint dwOpenMode, uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize, uint nDefaultTimeOut, SECURITY_ATTRIBUTES lpSecurityAttributes);

I've highlighted the last parameter because that is the one that I care about right now. The lpSecurityAttributes parameter determines what security the caller on the other end of the named pipe must have in order to connect to the pipe.

Here is the interoperable declaration for the SECURITY_ATTRIBUTES structure.

[StructLayout(LayoutKind.Sequential)]
class SECURITY_ATTRIBUTES {
int nLength;
IntPtr lpSecurityDescriptor;
int bInheritHandle;
}

Now, how do we create the security descriptor that is needed for this structure? The security descriptor is what contains the null DACL. The framework does supply us with a class for this called RawSecurityDescriptor. Here is the line of code to create the descriptor with a null DACL.

RawSecurityDescriptor gsd = new RawSecurityDescriptor(ControlFlags.DiscretionaryAclPresent, null, null, null, null);

Yep, that's all for that part. The tricky thing is that you have to set the DACLPresent flag even though you pass null in for the DACL (It's one of the other parameters to the constructor). This makes the class create a null DACL. If you don't pass in this flag you will get a restricted DACL that is set to the login of the current user and the Administrator only.

Now that the first step is done, how do we pass the RawSecurityDescriptor in the SECURITY_ATTRIBUTES structure to the CreateNamedPipe function? This is a bit messy, but it works.

// Build NULL DACL (Allow everyone full access)
RawSecurityDescriptor gsd = new RawSecurityDescriptor(ControlFlags.DiscretionaryAclPresent, null, null, null, null);

// Construct SECURITY_ATTRIBUTES structure
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES));
sa.bInheritHandle = 1;

// Get binary form of the security descriptor and copy it into place
byte[] desc = new byte[gsd.BinaryLength];
gsd.GetBinaryForm(desc, 0);
sa.lpSecurityDescriptor = Marshal.AllocHGlobal(desc.Length);
Marshal.Copy(desc, 0, sa.lpSecurityDescriptor, desc.Length);

// use the structure
CreateNamedPipe( yada, yada, yada,..., sa);

// Important!! Be sure to clean up after you use the structure
Marshal.FreeHGlobal(sa.lpSecurityDescriptor);
sa.lpSecurityDescriptor = IntPtr.Zero;

This code creates the null DACL and then copies the binary representation into memory where the SECURITY_ATTRIBUTES structure can reference it. Make sure you free the memory after you complete with the structure. I built the free into the Finalizer of the SECURITY_ATTRIBUTES class, but don't wait on the Finalizer to be invoked. I used the Disposable pattern as well to make sure that the memory was freed. Here is a complete listing of the class.

[StructLayout(LayoutKind.Sequential)]
internal class SECURITY_ATTRIBUTES : IDisposable {
internal int nLength;
internal IntPtr lpSecurityDescriptor;
internal int bInheritHandle;

public static SECURITY_ATTRIBUTES GetNullDacl() {
// Build NULL DACL (Allow everyone full access)
RawSecurityDescriptor gsd = new RawSecurityDescriptor(ControlFlags.DiscretionaryAclPresent, null, null, null, null);

// Construct SECURITY_ATTRIBUTES structure
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES));
sa.bInheritHandle = 1;

// Get binary form of the security descriptor and copy it into place
byte[] desc = new byte[gsd.BinaryLength];
gsd.GetBinaryForm(desc, 0);
sa.lpSecurityDescriptor = Marshal.AllocHGlobal(desc.Length); // This Alloc is Freed by the Disposer or Finalizer
Marshal.Copy(desc, 0, sa.lpSecurityDescriptor, desc.Length);

return sa;
}
public void Dispose() {
lock (this) {
if (lpSecurityDescriptor != IntPtr.Zero) {
Marshal.FreeHGlobal(lpSecurityDescriptor);
lpSecurityDescriptor = IntPtr.Zero;
}
}
}
~SECURITY_ATTRIBUTES() {
Dispose();
}
}

I hope this helps. Maybe somebody else will be luckier than me and happen upon this post rather than having to rediscover the method.