FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
Dobbs M-Dev
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
April 01, 2003
Tech Tips

(Page 1 of 3)
George Frasier
Misuse of MAX_PATH Can Cause Security Holes
by Shawn A. Van Ness Write Your Own Visual Studio .NET Custom Wizard
by Pablo Presedo

Duplicating Registry Keys with RegKeyDup
by Matthew Wilson

Tech Tips


Misuse of MAX_PATH Can Cause Security Holes
by Shawn A. Van Ness
shawnv@arithex.com

In the September 2002 issue of WDM, Matthew Wilson shared the following Tech Tip: "Don't forget to account for the NULL termination character when calculating path lengths." This is great advice, but if you care about writing secure code (and you do), it's not always enough. In some cases, a character array of size [MAX_PATH+1] is just as incorrect as a character array of size [MAX_PATH]. The naive use of MAX_PATH-sized buffers (especially on the stack) has been the cause of a great many buffer overrun attacks, and many other less obvious, indirect security holes.

According to the official documentation at http://msdn.microsoft.com/library/en-us/fileio/base/createfile.asp and http://msdn.microsoft.com/library/en-us/fileio/base/naming_a_file.asp, pathnames on NTFS-based filesystems can be up to 32,767 Unicode characters long (if the path is prefixed by \\?\). (The MAX_PATH constant is defined as 260.) Now, in practice it is very difficult to create a file or directory with a path longer than 260, but with new NTFS features such as reparse points, junction points, and so on, it's not impossible.

Anyway, hackers aren't often turned off by the difficulty of an attack...and coercing servers to generate over-long pathnames has been a longtime favorite approach. My advice to developers of the world: Search your entire source tree for "MAX_PATH," and open a code-bug for every hit. Then fix those bugs. Next, host a meeting to get your development team up to speed and out of the habit of using MAX_PATH entirely (and out of the habit of making any other such optimistic guesses about buffer sizes, in general). Virtually every Win32 function that returns a string provides some way to query for the size of that string beforehand — unfortunately, it's not always easy. Again, my advice would be to get out of the habit of calling complex Win32 functions in-line with one's code. Calls to functions such as WideCharToMultiByte(), for example, have extremely complex and delicate memory-management semantics, and are therefore extremely difficult to get right — even difficult to review for correctness! These functions should only be called within the scope of a well-tested wrapper. Back to the topic of pathnames: Even calling a relatively simple function such as GetTempPath() can take a surprising amount of code to implement properly (see Listing 1). An ounce of reuse is worth a pound of bug fixes!

Write Your Own Visual Studio .NET Custom Wizard
by Pablo Presedo
ppresedo@hotmail.com

I recently started working on an MFC project where I wanted to create multiple CFormViews that would live in COM DLLs. I knew the CFormViews would all look basically the same. Instead of cutting, pasting, and copying files, I thought it better to create a custom wizard to create these various CFormViews.

Microsoft's Visual Studio .NET has a wizard for creating a custom wizard. The custom wizard creates several files that you will need to modify to create your custom wizard:

default.htm
default.js
templates.inf
I started with default.htm because this file is the first one the user will interact with. The default.htm file presents the interface into which the user will enter information to be used in the creation of the project. You can modify the default.htm like you would any HTML file. The important thing to remember is to use the <SYMBOL> tag with your input elements. The custom wizard engine is dependent on using the <SYMBOL> tags for interacting with your wizards.

Here are some of the <SYMBOL> tags used in the custom wizard I have created.

<SYMBOL NAME='SOURCE_FILTER' TYPE="text" VALUE="cpp;cxx;c;def"></SYMBOL>
<SYMBOL NAME='INCLUDE_FILTER' TYPE="text" VALUE="hpp;hxx;h"></SYMBOL>
<SYMBOL NAME='FORM_NAME' TYPE="text" VALUE=''></SYMBOL>
<SYMBOL NAME='DEFINE_GUID_FORMAT' TYPE="text"></SYMBOL>
SOURCE_FILTER and INCLUDE_FILTER <SYMBOL> are special tags used with what are called "filters" in the custom wizard world. These filters are the different folders in the project. The SOURCE_FILTER tag would be used to designate a folder in a project as containing only files with the extensions cpp, cxx, c, or def. When using the AddFile function in the JavaScript file default.js, the AddFile function will add files with a cpp, cxx, c, or def into the source folder instead of the root folder of the project. It is important to notice that the '.' is missing from the extensions. If the '.' is included with the extension, then your filter will not work.

You will notice that the ID for the input element is the <SYMBOL> tag FORM_NAME:

<P><SPAN class="itemTextTop"> Form Name: <INPUT id="FORM_NAME" type="text" name="FormName"></SPAN></P>
After you have finished with setting up the interface to your custom wizard, you are ready to start modifying the templates.inf file. The templates.inf contains a list of files that make up the project that your custom wizard is going to create or copy to your project's main directory.

There are template directives you can use with the template files. In this example, I have only used the [!output] directive. For instance, if you look inside of root.h, you will see the following:

class C[!output FORM_NAME]View;

class C[!output FORM_NAME]Form : public ISMForm
{
...
}

DEFINE_GUID(CLSID_I[!output FORM_NAME]RecordSet,  
[!output DEFINE_GUID_FORMAT]);
This will output the FORM_NAME symbol value to create the class name as well as a CLSID for the COM object.

Now you are ready to start adding the JavaScript code to take the user-supplied information and create the project from your custom wizard. The custom wizard will create a default.js file.

The first place to start adding code is to default.htm. We add a CreateGuids function to create a GUID for the COM object being created. This function calls the FormatGuid function and sets the DEFINE_GUID_FORMAT symbol tag with the value. Later on, this symbol will be spit out via the [!output] template directive. The CreateGuids will be called from the InitDocument function.

Next is the default.js file, where we will make the remaining script changes. We start in the OnFinish function that creates the res subdirectory to store the rc2 file. To do this, we use FileSystemObject. After that, we modify the AddFilters function to add two more Filters. Remember, in the custom wizard world filters are the folders in a project that group files together. We will add an include filter and a resource filter.

After adding the filters to your custom wizard, you will want to modify the GetTargetName and AddFilesToCustomProj functions. The AddFilesToCustomProj function will call the GetTargetName function to determine what name to give to the files found in the template.inf file. The GetTargetName function is where you get the name to use for your various root files. The root files are template files that are customized by the use of template directive commands. The AddFilesToCustomProj function is where you can control the location your files are copied to. In the example that I have provided, I check to see if the template file being copied is root.rc2. If it is, I change the path to the project path plus the subdirectory res.

Finally, you should modify the compiler and linker settings. Do this by changing the AddConfig function. Here you can add, edit, or remove compiler and linker settings. You can also add additional build configurations such as a Unicode debug and release build configuration.

You are now ready to use your custom wizard. If after all this your custom wizard does not quite work as expected or gives you an error, you will want to debug it. To debug a custom wizard you will need to launch Visual Studio .NET twice. One instance will have your custom wizard solution loaded. The other will attempt to create a new project selecting your custom wizard. You will then attach to this copy of Visual Studio .NET by selecting the Debug menu and then Processes. When it prompts you with the types of programs, be sure to select "script" as one of them. You are now ready to set breakpoints and step through your script to determine what errors you have.

Your best sources of information on how to do things in a custom wizard are the various custom wizards provided by Microsoft. You can look in your ...\microsoft visual studio .net\vc7\vcwizards directory to find the various wizard files that make up the different custom wizards provided by Microsoft.

To set up the example, either extract the files from the two zip files using "Use folder names" or modify the following two files found in the sample zip files:

Data Form View.vsdir
Data Form View.vsz
Put these files in your ...\microsoft visual studio .net\vc7\vcprojects directory. The .vsdir file specifies the location of the wizard files. The complete example is included in this month's code archive.

Duplicating Registry Keys with RegKeyDup
by Matthew Wilson
matthew@synesis.com.au

Sometimes when I'm doing something like wrapping registry key handles in classes, it is necessary to duplicate a registry key. Although this has always been available in the registry API (even in Win16), it is not widely known; maybe because key duplication is uncommon and it relies on the often overlooked semantics of the RegOpenKey() and RegOpenKeyEx() functions.

#if defined(WIN32) || \
    defined(_WIN32)
inline HKEY RegKeyDup(HKEY hkey, REGSAM samDesired = KEY_ALL_ACCESS)
{
    HKEY    hkeyDup;
    LONG    res = ::RegOpenKeyEx(hkey, NULL, 0, samDesired, &hkeyDup);

    if(res != ERROR_SUCCESS)
    {
        hkeyDup = NULL;
    }

    return hkeyDup;
}
#else
inline HKEY RegKeyDup(HKEY hkey)
{
    HKEY    hkeyDup;
    LONG    res = ::RegOpenKey(hkey, NULL, &hkeyDup);

    if(res != ERROR_SUCCESS)
    {
        hkeyDup = NULL;
    }

    return hkeyDup;
}
#endif /* Win32 */

The implementation is very simple indeed. If RegOpenKey() or RegOpenKey() is called with the lpszSubKey parameter as NULL or pointing to the empty string, then the given key is opened; i.e., it is duplicated.

The implementation given includes the original 16-bit program along with the 32-bit version. The latter also allows a security access mask to be specified as the second parameter (the default is to ask for all permissions). Since it is a default parameter, this version is compatible with earlier 16-bit client code.

NOTE: To any 16-bit programmers still out there, remember to #include shellapi.h. See Listing 2 for the complete code.


George Frazier is a software engineer in the System Design and Verification group at Cadence Design Systems Inc. and has been programming for Windows since 1991. He can be reached at georgefrazier@yahoo.com.

1 | 2 | 3 Next Page
TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK