Using the Security Configuration Editor

Using the Security Configuration Editor

The Security Configuration Editor first shipped with service pack 4 for Windows NT 4 and is present by default on Windows 2000 and later. It consists of a pair of Microsoft Management Console (MMC) snap-ins and a command line application. Let's say that you've thought carefully about how to secure your application and that your application installs in a single directory and creates one registry key under HKEY_LOCAL_MACHINE\Software. First start MMC and add the Security Templates and Security Configuration And Analysis snap-ins, as shown in Figure 21-1.

figure 21-1 the add/remove snap-in window, showing the security templates and the security configuration and analysis snap-ins added to mmc.

Figure 21-1. The Add/Remove Snap-In window, showing the Security Templates and the Security Configuration And Analysis snap-ins added to MMC.

Next we need to create a custom security database and template. The tool won't let you create a database without applying a template, so that's the first step. Expand the Security Templates tree, right-click the %systemroot%\Security\Template, and choose New Template. Supply a name for this template. I named my new template null because it doesn't set anything at all. Figure 21-2 shows the MMC console after the new template is created.

figure 21-2 the mmc console, showing the null security template.

Figure 21-2. The MMC console, showing the null security template.

Next create a new configuration database. Right-click the Security Configuration And Analysis snap-in, and choose Open Database. Type in the name and path for the database you want to create. I used NewApp.sdb for this example. The Import Template dialog box, shown in Figure 21-3, will prompt you for a template to associate with the database. Choose the null template you just created.

figure 21-3 the import template dialog box, where you can specify a template to associate with the database.

Figure 21-3. The Import Template dialog box, where you can specify a template to associate with the database.

Next create a template that defines the settings your application needs. Precreate the registry key and a directory that you can use to define settings on. Go back to MMC, as shown in Figure 21-4, right-click the Registry portion of the template, and choose Add Key.

figure 21-4 the mmc console with the new template node expanded.

Figure 21-4. The MMC console with the new template node expanded.

Navigate the tree in the Select Registry Key dialog box until you locate your key, and set the permissions you'd like applied using the ACL editor tool. Now do the same thing with the File System folder. If you have individual files that need special permissions, you can set them here. Save your template, and close MMC so that it will release the database. If you open the template with Notepad, it will look like this:

[Unicode] Unicode=yes [Registry Values] [Registry Keys] "MACHINE\SOFTWARE\NewApp",0,"D:PAR(A;OICI;KA;;;BA)(A;CI;CCSWRC;;;WD) " [File Security] "E:\NewApp",0,"D:AR(A;OICI;FA;;;BA)(A;OICI;0x1f00e9;;;W D)" [Version] signature="$CHICAGO$" Revision=1

Edit any lines that point to the root of your installation directory (E:\NewApp, in this example), and change them to %newapp_install%. Next compile and run the following code. This sample code is also available with the book's sample files in the folder Secureco2\Chapter21\SecInstall.

/* This application takes a security template .inf file, substitutes a user-supplied directory for %newapp_install%, and writes it to a custom .inf file that you can apply to the directory your user chose. */ #define UNICODE #include <windows.h> #include <stdio.h> /* I really hate tracking all my code paths to make sure I don't leak handles, so I write lots of classes like this. */ class SmartHandle { public: SmartHandle() { Handle = INVALID_HANDLE_VALUE; } ~SmartHandle() { if(IsValid()) { CloseHandle(Handle); } } bool IsValid(void) { if(Handle != INVALID_HANDLE_VALUE && Handle != NULL) { return true; } else { return false; } } HANDLE Handle; }; /* Tired of having to convert arguments to UNICODE? Use wmain instead of main, and they'll be passed in as UNICODE. */ int wmain(int argc, WCHAR* argv[]) { SmartHandle hInput; SmartHandle hOutput; SmartHandle hMap; WCHAR* pFile; WCHAR* pTmp; WCHAR* pLast; DWORD filesize; DWORD dirlen; if(argc != 4) { wprintf(L"Usage is %s [input file], argv[0]); wprintf(L" [output file] [install directory]\n"); return -1; } dirlen = wcslen(argv[3]); hInput.Handle = CreateFile(argv[1], GENERIC_READ, 0, //Don't share the file. NULL, //Don't change the security. OPEN_EXISTING, //Fail if the file isn't present. FILE_ATTRIBUTE_NORMAL, // Just a normal file NULL); //No template if(!hInput.IsValid()) { wprintf(L"Cannot open %s\n", argv[1]); return -1; } DWORD highsize = 0; filesize = GetFileSize(hInput.Handle, &highsize); if(highsize != 0 filesize == ~0) { //The file is bigger than 4 GB - //what kind of .inf file is this??? wprintf(L"%s is too large to map or size not found\n", argv[1]); return -1; } /* Same as the previous function except that you always create the file */ hOutput.Handle = CreateFile(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(!hOutput.IsValid()) { wprintf(L"Cannot open %s\n", argv[2]); return -1; } //Now that we have the input and output files open, //map a view of the input file. //Memory-mapped files are cool and make many tasks easier. hMap.Handle = CreateFileMapping(hInput.Handle, //Open file NULL, //No special security PAGE_READONLY, //Read-only 0, //Don't specify max size 0, //or min size - will be size of file. NULL); //We don't need a name. if(!hMap.IsValid()) { wprintf(L"Cannot map %s\n", argv[1]); return -1; } //Start at the beginning of the file, and map the whole thing. pFile = (WCHAR*)MapViewOfFile(hMap.Handle, FILE_MAP_READ, 0, 0, 0); if(pFile == NULL) { wprintf(L"Cannot map view of %s\n", argv[1]); return -1; } //Now we've got a pointer to the whole file - //let's look for the string we want. pTmp = pLast = pFile; DWORD subst_len = wcslen(L"%newapp_install%"); while(1) { DWORD written, bytes_out; pTmp = wcsstr(pLast, L"%newapp_install%"); if(pTmp != NULL) { //Found the string. //How many bytes to write? bytes_out = (pTmp - pLast) * sizeof(WCHAR); if(!WriteFile(hOutput.Handle, pLast, bytes_out, &written, NULL) bytes_out != written ) { wprintf(L"Cannot write to %s\n", argv[2 ]); return -1; } //Now instead of %newapp_install%, print the actual dir. if(!WriteFile(hOutput.Handle, argv[3], dirlen * sizeof(WCHAR), &written, NULL) dirlen * sizeof(WCHAR) != written) { wprintf(L"Cannot write to %s\n", argv[2]); UnmapViewOfFile(pFile); return -1; } pTmp += subst_len; pLast = pTmp; } else { //Didn't find the string - write the rest of the file. bytes_out = (BYTE*)pFile + filesize - (BYTE*)pLast; if(!WriteFile(hOutput.Handle, pLast, bytes_out, &written, NULL) bytes_out != written) { wprintf(L"Cannot write to %s\n", argv[2]); UnmapViewOfFile(pFile); return -1; } else { //We're done. UnmapViewOfFile(pFile); break; } } } //All the rest of our handles close automagically. return 0; }

Pretty cool, huh? I bet you thought I was going to do something lame like ask your users to edit the .inf file themselves. That wouldn't do any good; users don't do complicated steps, just like they usually don't Read The Fine Manual. Now that you've taken your user-supplied directory path, simply run the following command:

[e:\]secedit /configure /db NewApp.sdb /cfg out.inf /areas REGKEYS FILESTORE /verbose

Now your application installation will be done securely the only step you have left is to verify that the permissions you set up were really what you wanted. You can also leave the Out.inf file in case the user wants to restore the application security settings to default. Once you've done the hard part (thinking) and set up the database and .inf files, the rest of it can easily run from within your installation scripts. Given my past experiences doing this the hard way for an application that had to support Windows NT 3.51 and 4, the time this approach will save you ought to be worth the price of this book!



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2001
Pages: 286

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net