tag:blogger.com,1999:blog-133500472024-03-14T07:55:54.733-05:00The Platypus Developer's CornerRandom bits of information regarding the Platypus Billing System.<br>Not necessarily what you would call useful, but information none the less.Unknownnoreply@blogger.comBlogger27125tag:blogger.com,1999:blog-13350047.post-82273832969033167092015-02-21T18:00:00.001-06:002015-02-21T19:05:13.664-06:00Compiling OpenSSL, curl, and zlib on WindowsGetting these libraries compiled on Windows was surprisingly easy. Cross-platform support has come a long way. <a href="https://www.openssl.org/">OpenSSL</a> required the most setup. Both <a href="http://www.activestate.com/activeperl">ActiveState Perl</a> and <a href="http://www.nasm.us/">NASM</a> were necessary for the build process. Also, this assumes there is a temporary compile folder and then an install folder. The temporary compile folder in these examples has the version number afterward. The install folder is just the product name.<br />
<br />
<b><a href="http://www.zlib.net/">zlib</a></b><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjle-MR6fDb-xFRwLwhugRploW1XrxZekf3A57w2eAWm96qyYpZXDOQ9_zTCfAYOe80y5mHufJwdvqlsFWnd6Vq3XMdouXxH3bVYszXpyU5_dGHzVnJhx42KFTa4CzybTcjOYvovA/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> mkdir \projects\zlib
mkdir \projects\zlib\bin
mkdir \projects\zlib\include
mkdir \projects\zlib\lib
cd \projects\zlib-1.2.8\
nmake /f .\win32\Makefile.msc
copy zlib.h ..\zlib\include
copy zconf.h ..\zlib\include
copy *.lib ..\zlib\lib
copy *.dll ..\zlib\bin
</code></pre>
<br />
<b><a href="http://curl.haxx.se/">curl</a></b><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjle-MR6fDb-xFRwLwhugRploW1XrxZekf3A57w2eAWm96qyYpZXDOQ9_zTCfAYOe80y5mHufJwdvqlsFWnd6Vq3XMdouXxH3bVYszXpyU5_dGHzVnJhx42KFTa4CzybTcjOYvovA/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> cd \projects\curl-7.40.0\
nmake /f Makefile.vc mode=dll MACHINE=x86
move .\builds\libcurl-vc-x86-release-dll-ipv6-sspi-winssl ..\..\libcurl
</code></pre>
<br />
<b><a href="https://www.openssl.org/">OpenSSL (static)</a></b><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjle-MR6fDb-xFRwLwhugRploW1XrxZekf3A57w2eAWm96qyYpZXDOQ9_zTCfAYOe80y5mHufJwdvqlsFWnd6Vq3XMdouXxH3bVYszXpyU5_dGHzVnJhx42KFTa4CzybTcjOYvovA/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> cd \projects\openssl-1.0.2
perl Configure VC-WIN32 --prefix=c:/projects/openssl
.\ms\do_nasm
nmake -f .\ms\nt.mak
nmake -f .\ms\nt.mak test
nmake -f .\ms\nt.mak install
</code></pre>
<br />
<b><a href="https://www.openssl.org/">OpenSSL (dll)</a></b><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjle-MR6fDb-xFRwLwhugRploW1XrxZekf3A57w2eAWm96qyYpZXDOQ9_zTCfAYOe80y5mHufJwdvqlsFWnd6Vq3XMdouXxH3bVYszXpyU5_dGHzVnJhx42KFTa4CzybTcjOYvovA/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> cd \projects\openssl-1.0.2
perl Configure VC-WIN32 --prefix=c:/projects/openssl
.\ms\do_nasm
nmake -f .\ms\ntdll.mak
nmake -f .\ms\ntdll.mak test
nmake -f .\ms\ntdll.mak install
</code></pre>
<br />
I may expand on this post. There are a few other libraries that I'd like to use and keeping instructions in one place seems like a good idea.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-85389056728100045852015-02-20T15:35:00.002-06:002015-02-20T18:26:07.130-06:00Problems using the Command Line Install on SQL Server 2014 ExpressThe installation sets for SQL Server Express are actually wrapper executable, which basically means they are large zip files which contain the setup files. So, the first thing that happens after running it is that all the files are extracted to a temporary directory and then the Setup.exe is executed using the command line parameters passed to the wrapper.<br />
<br />
Unfortunately, there are a few bugs in the wrapper executable for SQL Server 2014 RTM. These seem to be exclusive to SQL Server 2014 RTM, and according to Microsoft <a href="https://connect.microsoft.com/SQLServer/feedback/details/878374/sql-server-2014-express-qs-parameter-requires-user-input">will be fixed in service pack 1</a>. In previous versions of the SQL Server Express installation sets, the extract folder is randomly generated and the files are automatically extracted.<br />
<br />
<b>
Because of this, you can run the wrapper in one of two ways.</b><br />
<ol>
<li>Using the same command line parameters as I used in SQL Server 2008 Express and 2012 Express, I am prompted for an extract folder. Once extracted, the Setup.exe is correctly executing using command line parameters passed to the executable. This has the down side of making completely automated installs impossible. </li>
<li>Using command line parameters exclusive to the wrapper, I can specify an extract folder. This has the down side of ignoring any other command line parameters. So, I'm going to have to extract the files and then run Setup.exe separately.</li>
</ol>
<b>
Command line parameters supported by the wrapper</b><br />
<div>
<ul>
<li>/Q - Quiet mode. This is the same as Quiet mode for Setup.exe</li>
<li>/U - Progress Bar mode. This displays a progress bar as the files are extracted.</li>
<li>/X:<PATH> - The Extract Folder where the files are extracted. This last parameter has a few caveats. </li>
</ul>
<b>
Extract Folder Parameter</b></div>
<div>
<ul>
<li>The parameter must be the last parameter. Anything after that is considered part of the path.</li>
<li>The parameter must be followed by a colon and then followed by the path.</li>
<li>There must be no space between the X and the colon or the colon and the path.</li>
</ul>
<div>
What this means is that anyone wanting to automate the installation of SQL Server will need to first extract the files. Then, run Setup.exe separately. Afterward, any temporary folder and files will need to be cleaned up.</div>
<div>
<br /></div>
<div>
While this isn't a huge burden for developers, it definitely qualifies as annoying. It did involve a couple of extra days worth of testing to make sure I covered all the bases.</div>
<div>
<br /></div>
</div>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-26205863436191689732015-02-19T15:03:00.001-06:002015-02-20T15:42:42.801-06:00SSL/TLS Protocols Supported by WindowsI know I'm a bit slow out of the gate here. This post is coming much later than it should have. Anyway, I wanted to find a list of TLS/SSL protocols supported by Windows. Unfortunately, that statement is rather dubious.<br />
<br />
It should be two separate questions. What protocols are supported by IIS; and what protocols are supported by Internet Explorer. The answer to the first is very simple.<br />
<br />
IIS on Windows XP/2003/Vista/2008 support<br />
<br />
<ul>
<li>SSL2</li>
<li>SSL3 </li>
<li>TLS1</li>
</ul>
<br />
IIS on Windows 7/2008R2/8/2012/8.1/2012R2 support<br />
<br />
<ul>
<li>SSL2</li>
<li>SSL3</li>
<li>TLS1</li>
<li>TLS1.1</li>
<li>TLS1.2</li>
</ul>
<br />
If you are using IIS on an older version of Windows than 2003, please don't. Considering the number of vulnerabilities in IIS on Windows 2000 over the years and the fact that the OS is no longer supported in any way by Microsoft, you shouldn't even be it.<br />
<br />
The answer to the second question is a little less simple because each version of Internet Explorer is built to run on multiple versions of Windows. So, it's more along a combination of the version of Windows plus the version of Internet Explorer.<br />
<br />
A full comprehensive table <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers">is listed on Wikipedia</a> of all browsers with helpful references to vulnerabilities and how those browsers are affected by them. The best situation for Internet Explorer users is using Internet Explorer 11 on Windows 8.1. Users of Internet Explorer 8 (or greater) on Windows 7 (or greater) can get just as secure a setup as those on IE11/Win8.1 by making a few option changes.<br />
<br />
<span style="font-size: large;"><b>References</b></span><br />
<br />
<ul>
<li> <a href="http://blogs.msdn.com/b/kaushal/archive/2011/10/02/support-for-ssl-tls-protocols-on-windows.aspx">Support for SSL/TLS protocols on Windows</a></li>
<li><a href="http://support.microsoft.com/kb/245030">How to restrict the use of certain cryptographic algorithms and protocols in Schannel.dll</a></li>
<li><a href="http://blogs.msdn.com/b/kaushal/archive/2014/10/22/poodle-vulnerability-padding-oracle-on-downgraded-legacy-encryption.aspx">POODLE Vulnerability: Padding Oracle on Downgraded Legacy Encryption</a></li>
<li><a href="http://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers">Wikipedia - Transport Layer Security</a></li>
</ul>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-51337249230130088142015-01-19T22:37:00.001-06:002015-01-19T22:39:02.775-06:00SQL Server Driver Versions, According to MS-TDSWhile playing around with <a href="https://www.wireshark.org/">Wireshark</a> and <a href="http://klonkers.blogspot.com/2015/01/making-something-useful-out-of-ms-tds.html">MS-TDS</a>, I had a chance to see the different version numbers being sent to the server by the various SQL Server drivers. I thought this might give some insight into determining how compatibility is determined. It didn't, but I thought I would share what the versions being sent by the client actually are.<br />
<div>
<br /></div>
<div>
SQL Server (SQLSRV32.DLL) on Windows Vista SP2 </div>
<div>
Hex: 0x08,0x00,0x01,0x55</div>
<div>
Parsed: 08.00.341<br />
Product Version (on the dll): 6.0.6002.18005</div>
<div>
<br /></div>
<div>
<a href="http://www.microsoft.com/en-us/download/details.aspx?id=24793">SQL Native Client 9 (SQLNCLI.DLL)</a></div>
<div>
Hex: 0x09,0x00,0x0b,0xe2</div>
<div>
Parsed: 09.00.3042<br />
Product Version (on the dll): 9.0.3042.0</div>
<div>
<br /></div>
<div>
<a href="http://www.microsoft.com/en-us/download/details.aspx?id=44272">SQL Native Client 10 (SQLNCLI10.DLL)</a> for SQL Server 2008 R2 SP3</div>
<div>
Hex: 0x00,0x2e,0x00,0x00</div>
<div>
Parsed: 00.46.0000<br />
Product Version (on the dll): 10.50.6000.34</div>
<div>
<br /></div>
<div>
<a href="http://www.microsoft.com/en-us/download/details.aspx?id=43339">SQL Native Client 11 (SQLNCLI11.DLL)</a> for SQL Server 2012 SP1</div>
<div>
Hex: 0x0b,0x00,0x0b,0xb8</div>
<div>
Parsed: 11.00.3000<br />
Product Version (on the dll): 11.0.3000.0</div>
<div>
<br /></div>
<div>
<a href="http://www.microsoft.com/en-us/download/details.aspx?id=36434">ODBC Driver 11 for SQL Server</a></div>
<div>
Hex: 0x0b,0x00,0x08,0xde</div>
<div>
Parsed: 11.00.2270<br />
Product Version (on the dll): 11.0.2270.0</div>
<div>
<br /></div>
<div>
For the most part, the version numbers match up with the "Product Version" on the dll, except the built-in SQL Server driver and SQL Native Client 10.<br />
<br />
The built-in SQL Server driver is a holdover from the old days of <a href="http://en.wikipedia.org/wiki/Microsoft_Data_Access_Components">MDAC</a>, where you had to manually install drivers onto Windows to get connected. Starting with Windows Vista, the built-in SQL Server driver truly became built into the OS. From that point forward, the Product Version on the dll would always match the OS.<br />
<br />
With the SQL Native Client 10, I have no idea what's going on there. Considering the version number sent by SQL Native Client 10, I can only assume that the SQL Server ignores the version number being sent and that other features determine compatibility. Perhaps compatibility is left strictly to the client. On the client side, I'm guessing that drivers make a number of assumptions based on the server version being sent back as well as various function calls, like the ODBC <a href="http://msdn.microsoft.com/en-us/library/ms714632">SQLGetTypeInfo</a>, <a href="http://msdn.microsoft.com/en-us/library/ms709291">SQLGetFunctions</a>, and <a href="http://msdn.microsoft.com/en-us/library/ms711681">SQLGetInfo</a> functions.<br />
<br />
I think I've been <a href="http://xkcd.com/356/">nerd sniped</a> again.</div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-13350047.post-30927255655351789192015-01-14T22:12:00.001-06:002015-01-19T21:57:13.141-06:00Making something useful out of the MS-TDS PRELOGIN packet (SQLPing)I've been playing around with the low level SQL Server network protocols. These are officially known as [<a href="http://msdn.microsoft.com/en-us/library/dd304523.aspx">MS-TDS] Tabular Data Stream Protocol</a> and <a href="http://msdn.microsoft.com/en-us/library/cc219703.aspx">[MC-SQLR] SQL Server Resolution Protocol</a> and are fully documented on the <a href="http://msdn.microsoft.com/en-us/library/cc216517.aspx">Microsoft Protocols</a> web site. Unfortunately, like every other protocol and RFC I've ever read, comprehension is not easy.<br />
<br />
This interest mainly comes from wanting to understand the <a href="http://www.sqlsecurity.com/downloads">SQLPing</a> utility written by <a href="http://www.sqlsecurity.com/">Chip Andrews</a>. To put is simply, SQLPing <a href="http://xkcd.com/356/">nerd sniped</a> me. I've known about and used this little utility on a number of occasions, but I never had the chance to dig into it. After playing with the code and reading over the protocol, I wanted to share and translate tech-speak into something human friendly. This particular post is going to cover the <span style="font-family: Courier New, Courier, monospace;"><a href="http://msdn.microsoft.com/en-us/library/dd357559.aspx">PRELOGIN</a> </span>message in MS-TDS. I'll cover MC-SQLR in a separate post.<br />
<br />
<h2>
The SQL Handshake</h2>
When connecting to a SQL Server, the first thing that happens after connecting is a <span style="font-family: Courier New, Courier, monospace;">PRELOGIN</span> exchange. This happens before any authentication or encryption. It's a knock on the door, which allows the SQL Server and the client to check each other out to see if they are compatible with each other. If the SQL Server can't understand what you send, it kills the connection right then and there - long before any authentication is attempted.<br />
<br />
After a successful <span style="font-family: Courier New, Courier, monospace;">PRELOGIN</span>, the client can attempt a second <span style="font-family: Courier New, Courier, monospace;">PRELOGIN</span> for wrapping a SSL/TLS handshake to start encrypting the connection. Regardless, after the <span style="font-family: Courier New, Courier, monospace;">PRELOGIN</span>, the connection is authenticated using <span style="font-family: Courier New, Courier, monospace;"><a href="http://msdn.microsoft.com/en-us/library/dd304019.aspx">LOGIN7</a></span>. Finally, if everything has been successful, the client can begin to execute SQL statements.<br />
<br />
Microsoft was kind enough to provide a <a href="http://msdn.microsoft.com/en-us/library/dd358340.aspx">flowchart</a>, as well, for anyone interested in how the connection is fully negotiated.<br />
<h2>
The PRELOGIN Request & Response</h2>
The structure of the packet is a fairly simple binary format. It can be broken down into three main parts. First the packet header, next the token list, and finally the token data. The tokens are data containing a combination of compatibility and debug information.<br />
<br />
One of those tokens is a version numbers. For the client, the driver version is sent. For the server, the <a href="https://support.microsoft.com/kb/321185">product version</a> is returned. In fact, besides the underlying packet structure, the version is the minimum amount of information that must be sent between client and server.<br />
<br />
Here is a bare-bones example of a <span style="font-family: Courier New, Courier, monospace;">PRELOGIN </span>request packet in CSharp. It contains the minimum amount of information required to get a response from the server.<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjle-MR6fDb-xFRwLwhugRploW1XrxZekf3A57w2eAWm96qyYpZXDOQ9_zTCfAYOe80y5mHufJwdvqlsFWnd6Vq3XMdouXxH3bVYszXpyU5_dGHzVnJhx42KFTa4CzybTcjOYvovA/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;">var request = new byte[]
{
// Start Packet Header // 0x00 - 0x08
0x12, // PRELOGIN packet header
0x01, // Status (EOM) (last packet in message)
0x00,0x14, // Packet Length (uint16)
0x00,0x00, // Spid (uint16)
0x00, // Packet (uint8)
0x00, // Window (ignored; always 0x00)
// End Packet Header
// Start Token List // 0x09 - 0x0e
0x00, // VERSION token
0x00,0x06, // Offset Position (from Start Data Header)
0x00,0x06, // Data Length (uint32 + uint16)
0xff, // TERMINATOR token
// End Token List
// Start Data Content // 0x0f - 0x14
0x08,0x00,0x01,0x55, // UL_VERSION (driver 8.00.341)
0x00,0x00, // US_SUBBUILD (always zero)
// End Data Content
};</code></pre>
<br />
Likewise, here is a bare-bones example of a <span style="font-family: Courier New, Courier, monospace;">PRELOGIN</span> response packet in C#. In fact, if you compare the request and the response packet, they contain the same structure and data, although the version numbers and packet type are different.<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjle-MR6fDb-xFRwLwhugRploW1XrxZekf3A57w2eAWm96qyYpZXDOQ9_zTCfAYOe80y5mHufJwdvqlsFWnd6Vq3XMdouXxH3bVYszXpyU5_dGHzVnJhx42KFTa4CzybTcjOYvovA/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;">var response = new byte[]
{
// Start Packet Header // 0x00 - 0x08
0x04, // PRELOGIN response packet header
0x01, // Status (EOM) (last packet in message)
0x00,0x14, // Packet Length (uint16)
0x00,0x00, // Spid (uint16)
0x01, // Packet (uint8)
0x00, // Window (ignored; always 0x00)
// End Packet Header
// Start Token List // 0x09 - 0x0e
0x00, // VERSION token
0x00,0x06, // Offset Position (from Start Data Header)
0x00,0x06, // Data Length (uint32 + uint16)
0xff, // TERMINATOR token
// End Token List
// Start Token Data // 0x0f - 0x14
0x0c, 0x00, 0x07, 0xd0, // UL_VERSION (server version 12.00.2000)
0x00, 0x00 // US_SUBBUILD (always zero)
// End Token Data
};</code></pre>
<br />
<h2>
<span style="font-family: inherit;">The Packet Header</span></h2>
<div>
<span style="font-family: inherit;">The packet header contains six pieces of information, stored in eight bytes.</span></div>
<div>
<ol>
<li><a href="http://msdn.microsoft.com/en-us/library/dd304214.aspx">Type</a> - The type of message being sent. In the case of <span style="font-family: Courier New, Courier, monospace;">PRELOGIN</span>, the client will always send 0x12 (<span style="font-family: Courier New, Courier, monospace;">PRELOGIN</span>) and the server will always send 0x04 (<span style="font-family: Courier New, Courier, monospace;">TABULAR RESULT</span>).</li>
<li><a href="http://msdn.microsoft.com/en-us/library/dd358342.aspx">Status</a> - The state of the message. In this case, both the client and server will always send 0x01 (<span style="font-family: Courier New, Courier, monospace;">EOM</span><span style="font-family: Georgia, Times New Roman, serif;"> </span>or end of message), meaning this is the last packet in the message.</li>
<li><a href="http://msdn.microsoft.com/en-us/library/dd304803.aspx">Length</a> - The length of the packet - as an unsigned short - from the start of the packet header to the end of the token data.</li>
<li><a href="http://msdn.microsoft.com/en-us/library/dd305266.aspx">SPID</a> - The session id for the connection - as an unsigned short. In this case, because a session id is not assigned until after authentication occurs, this will always be zero.</li>
<li><a href="http://msdn.microsoft.com/en-us/library/dd358474.aspx">PacketID</a> - The index of the packet in the message. For messages spread across multiple packets, this would be incremented for each packet sent (mod 255). In this case, since we are only sending an receiving a single packet, this will always be zero. This is largely unused and can be ignored by always setting to zero.</li>
<li><a href="http://msdn.microsoft.com/en-us/library/dd305240.aspx">Window</a> - Unused. This will always be zero.</li>
</ol>
<h2>
The Token Header</h2>
</div>
The token header contains two or more tokens, as well as descriptive information about the tokens. For the <span style="font-family: Courier New, Courier, monospace;">PRELOGIN </span>packet, there are a total of nine different tokens supported. Actually, it's probably better to say there are eight tokens and a <span style="font-family: Courier New, Courier, monospace;">TERMINATOR</span> "token", which marks the end of the list of tokens. Besides the <span style="font-family: Courier New, Courier, monospace;">TERMINATOR</span>, each token is followed by an offset and a length. The token itself is a single byte, while the offset and length are both unsigned shorts.<br />
<br />
The offset contains the starting point in the packet body - ignoring the packet header - where the data is stored. In the example above, the <span style="font-family: Courier New, Courier, monospace;">VERSION</span> data is stored at 0x0006, which is six bytes after the first token. I'm assuming this, but this would allow a more efficient coding in the network library by separating reading the packet header from the packet body. The packet header will always be eight bytes, while the remainder of the packet will vary.<br />
<br />
Also, because the <span style="font-family: Courier New, Courier, monospace;">VERSION</span> token is the first token in packet, the data will also be the first after the <span style="font-family: Courier New, Courier, monospace;">TERMINATOR</span>. This makes the version fairly easy to find since it will be the first six bytes after the 0xFF.<br />
<br />
The length contains the number of bytes used by the token data and can be zero. In the example above, the <span style="font-family: Courier New, Courier, monospace;">VERSION</span> data occupies six bytes (0x0006) in the token data block.<br />
<br />
<ul>
<li><span style="color: #2a2a2a; line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">VERSION</span><span style="font-family: inherit;"> - The version and the only required token, other than the terminator. For the client, this represents the driver version, while on the server, it represents the product version. The version is stored across as a unsigned long, followed by an unsigned short. More acccurately, it is stored in the form of major version (byte), minor version (byte), build (unsigned short), minor build (unsigned short, always 0x0000).</span></span></li>
<li><span style="color: #2a2a2a; line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">ENCRYPTION</span> - Contains one of four values. This setting is used in the negotiation between the client and the server to determine if a SSL/TLS handshake will follow the <span style="font-family: Courier New, Courier, monospace;">PRELOGIN</span><span style="font-family: inherit;">. In this case, the value is not important, but the best setting to use is </span></span><span style="color: #2a2a2a;"><span style="line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">ENCRYPT_OFF</span><span style="font-family: inherit;"> (0x00), since this will return the server's </span><span style="font-family: Courier New, Courier, monospace;">ENCRYPTION</span><span style="font-family: inherit;"> setting.</span></span></span></li>
<li><span style="color: #2a2a2a; line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">INSTOPT</span> - For the client, this represents a NUL terminated string containing the instance name of the server. For the server, it is a booleaning representing a success (0x00) or failure (0x01) whether the instance name passed by the client matches the one on the server.</span></li>
<li><span style="color: #2a2a2a;"><span style="line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">THREADID</span> - An unsigned long used for debug purposes, representing the client application thread.</span></span></li>
<li><span style="color: #2a2a2a;"><span style="line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">MARS</span> - A boolean to enable or disable <a href="http://msdn.microsoft.com/en-us/library/cfa084cz.aspx">Multiple Active Result Sets</a>. According to the people at <a href="http://www.freetds.org/">FreeTDS</a>, there is <a href="http://www.freetds.org/mars.html">No Earthly Reason for MARS</a>. I won't argue. It's not relevant for this discussion, anyway and only works on <a href="http://msdn.microsoft.com/en-us/library/h32h3abf(v=vs.80).aspx">SQL Server 2005 or greater</a> when using SQL Native Client drivers or the <a href="http://www.microsoft.com/en-us/download/details.aspx?id=36434">ODBC driver for SQL Server 11</a>.</span></span></li>
<li><span style="color: #2a2a2a;"><span style="line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">TRACEID</span> - A 16 byte <a href="http://en.wikipedia.org/wiki/Globally_unique_identifier">GUID</a>, followed by a 20 byte Activity Id used for debug purposes. I have only seen this token when using SQL Native Client drivers. </span></span><span style="color: #2a2a2a; line-height: 18px;">Again, not relevant for this discussion.</span></li>
<li><span style="color: #2a2a2a;"><span style="line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">FEDAUTHREQUIRED</span> - A boolean to enable (0x01) or disable (0x00) <a href="http://msdn.microsoft.com/en-us/library/hh446535.aspx">Federated Authentication</a>. This is later used in the authentication process. I'm not sure what this is; but it's not relevant for this discussion.</span></span></li>
<li><span style="color: #2a2a2a;"><span style="line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">NONCEOPT</span> - A 32 bit <a href="http://en.wikipedia.org/wiki/Cryptographic_nonce">nonce</a> used with Federated Authentication.</span></span></li>
<li><span style="color: #2a2a2a;"><span style="line-height: 18px;"><span style="font-family: Courier New, Courier, monospace;">TERMINATOR</span> - A single byte containing 0xFF. This represents the end of the token header and the beginning of the token data. Unlike other tokens, it is not followed by an offset or a length.</span></span></li>
</ul>
<br />
<h2>
Additional Examples</h2>
<div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjle-MR6fDb-xFRwLwhugRploW1XrxZekf3A57w2eAWm96qyYpZXDOQ9_zTCfAYOe80y5mHufJwdvqlsFWnd6Vq3XMdouXxH3bVYszXpyU5_dGHzVnJhx42KFTa4CzybTcjOYvovA/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;">var response1 = new byte[] // Four token response
{
// Start Packet Header // 0x00 - 0x08
0x04, // PRELOGIN response packet header
0x01, // Status (EOM) (last packet in message)
0x00,0x25, // Packet Length (UInt16)
0x00,0x00, // Spid (uint16)
0x01, // Packet (uint8)
0x00, // Window (ignored; always 0x00)
// End Packet Header
// Start Token List // 0x09 - 0x14
0x00, // VERSION token
0x00,0x15, // Data Offset (UInt16) (from Start Data Header)
0x00,0x06, // Data Length (UInt16)
0x01, // ENCRYPTION token
0x00,0x1b, // Data Offset
0x00,0x01, // Data Length
0x02, // INSTOPT token
0x00,0x1c, // Data Offset
0x00,0x01, // Data Length
0x03, // THREADID token
0x00,0x1d, // Data Offset
0x00,0x00, // Data Length
0xff, // TERMINATOR token
// End Token List
// Start Token Data // 0x15 - 0x25
0x08, 0x00, 0x07, 0xf7, // UL_VERSION (08.00.2039)
0x00, 0x00, // US_SUBBUILD (always zero)
0x00, // ENCRYPTION (ENCRYPT_OFF)
0x00 // INSTOPT (SUCCESS)
// End Token Data
};
var response = new byte[] // Five token response
{
// Start Packet Header // 0x00 - 0x08
0x04, // PRELOGIN response packet header
0x01, // Status (EOM) (last packet in message)
0x00,0x30, // Packet Length (UInt16)
0x00,0x00, // Spid (uint16)
0x01, // Packet (uint8)
0x00, // Window (ignored; always 0x00)
// End Packet Header
// Start Token List // 0x09 - 0x26
0x00, // VERSION token
0x00,0x1f, // Data Offset (UInt16) (from Start Data Header)
0x00,0x06, // Data Length (UInt16)
0x01, // ENCRYPTION token
0x00,0x25, // Data Offset
0x00,0x01, // Data Length
0x02, // INSTOPT token
0x00,0x26, // Data Offset
0x00,0x01, // Data Length
0x03, // THREADID token
0x00,0x27, // Data Offset
0x00,0x00, // Data Length
0x04, // MARS token
0x00,0x27, // Data Offset
0x00,0x01, // Data Length
0x05, // TRACEID token
0x00,0x28, // Data Offset
0x00,0x00, // Data Length
0xff, // TERMINATOR token
// End Token List
// Start Token Data // 0x27 - 0x30
0x0c, 0x00, 0x07, 0xd0, // UL_VERSION (12.00.2000)
0x00, 0x00, // US_SUBBUILD (always zero)
0x00, // ENCRYPTION (ENCRYPT_OFF)
0x00, // INSTOPT (SUCCESS)
0x00 // MARS (OFF)
// End Token Data
};</code></pre>
<br /></div>
<h2>
Example CSharp to Retrieve the SQL Product Version</h2>
<div>
On to the most useful bit in this post. The minimal set of code to retrieve the product version of the SQL Server. The only requirement is knowing the IP address and port for the SQL Server.<br />
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjle-MR6fDb-xFRwLwhugRploW1XrxZekf3A57w2eAWm96qyYpZXDOQ9_zTCfAYOe80y5mHufJwdvqlsFWnd6Vq3XMdouXxH3bVYszXpyU5_dGHzVnJhx42KFTa4CzybTcjOYvovA/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;">using System; // Exception
using System.Net; // IPAddress
using System.Net.Sockets; // TcpClient, NetworkStream
namespace Example
{
public static class SqlClient
{
public static Version Prelogin(IPAddress address, int port)
{
var data = new byte[]
{
// Start Packet Header // 0x00 - 0x08
0x12, // PRELOGIN packet header
0x01, // Status (EOM) (last packet in message)
0x00,0x14, // Packet Length (uint16)
0x00,0x00, // Spid (uint16)
0x00, // Packet (uint8)
0x00, // Window (ignored; always 0x00)
// End Packet Header
// Start Data Header // 0x09 - 0x0e
0x00, // VERSION token
0x00,0x06, // Offset Position (from Start Data Header)
0x00,0x06, // Data Length (uint32 + uint16)
0xff, // TERMINATOR token
// End Data Header
// Start Data Content // 0x0f - 0x14
0x08,0x00,0x01,0x55, // UL_VERSION (8.00.341)
0x00,0x00, // US_SUBBUILD (always zero)
// End Data Content
};
using (var client = new TcpClient())
{
client.Connect(address, port);
using (NetworkStream stream = client.GetStream())
{
var bytesread = 0;
var bytespending = 0;
stream.Write(data, 0, data.Length);
// Read the response header
var responseheader = new byte[8];
bytesread = stream.Read(responseheader, 0, responseheader.Length);
// Double check to ensure the header contains useful data
if (bytesread != 8)
throw new Exception("A header must be 8 bytes.");
if (responseheader[0] != 0x04)
throw new Exception("A header must start with 0x04");
// Read the response body
bytespending = (responseheader[2] << 8) + responseheader[3] - 8;
var responsebody = new byte[bytespending];
bytesread = stream.Read(responsebody, 0, responsebody.Length);
// Double check to ensure the body contains useful data
if (bytesread != bytespending)
throw new Exception("The header bytes must match packet size.");
if (responsebody[0] != 0)
throw new Exception("The VERSION token must be the first token.");
var offset = (responsebody[1] << 8) + responsebody[2];
if (offset + 6 > bytesread)
throw new Exception("The VERSION data starts or ends after the packet.");
if (responsebody[3] != 0 || responsebody[4] != 6)
throw new Exception("The VERSION token must be 6 bytes long.");
return new Version(
responsebody[offset],
responsebody[offset + 1],
((responsebody[offset + 2] << 8) + responsebody[offset + 3])
);
}
}
}
}
}</code></pre>
<div>
<br />
<b>Update (January 19, 2015):</b> Updated source code using some friendly <a href="http://codeformatter.blogspot.com/">code formatting</a>.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-38908291978660819522013-09-28T02:03:00.002-05:002013-09-28T02:04:00.524-05:00Virtual Machines, Snapshots and Domain MembershipI have a number of <a href="http://www.vmware.com/products/vsphere-hypervisor/">virtual machines</a> that I use for <a href="http://en.wikipedia.org/wiki/Quality_assurance">QA</a>. All of these machines have <a href="http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1015180">snapshots for easy rollback</a> and all are members in an <a href="http://technet.microsoft.com/en-us/library/cc770946">Active Directory (AD) domain</a>. One of my goals has been to allow all the users in the domain to have administrative rights for these virtual machines, but getting that working has encountered a few hiccups.<br />
<br />
Every once in a while, the domain membership breaks. When trying to log in with a domain login through <a href="http://en.wikipedia.org/wiki/Remote_Desktop_Protocol">RDP</a>, I get an authentication error, specifically: <b>The Local Security Authority cannot be contacted</b>. When trying to log into the machine directly (through the vSphere Client) using the same domain login, I get a different a different - but also vague error: <b>The trust relationship between this workstation and the primary domain failed</b>.<br />
<br />
The short and recommended answer is to <a href="http://support.microsoft.com/kb/216393">rejoin the machine to the domain</a>. This can be done in <a href="http://www.implbits.com/about/blog/tabid/78/post/don-t-rejoin-to-fix-the-trust-relationship-between-this-workstation-and-the-primary-domain-failed/default.aspx">several creative ways</a> in addition to Microsoft's recommendation, but it doesn't really solve the problem. Microsoft's article does give me a little more insight, though. "For Windows 2000 or Windows XP, the default computer account password change period is every 30 days." The article was written many, many moons ago, but this behavior hasn't changed with newer versions of Windows.<br />
<br />
Roughly translated, every 30 days or so, a Windows machine that is part of a domain, renegotiates its connection to the domain. Basically, Windows changes its "machine password" on the domain controller. This new password is only known by the domain controller(s) and the machine. What this means for me is that every time I rollback one of my QA virtual machines, Windows loses its new password and goes back to using its previous password - the one created before the snapshot.<br />
<br />
Considering these machines are going to be rolled back to a snapshot often, having to rejoin them to the domain after every rollback is not a viable option. A better solution would be to stop the trust from breaking in the first place. This is actually something I can accomplish pretty quickly thanks to the article <a href="http://blogs.technet.com/b/askds/archive/2009/02/15/test2.aspx">Machine Account Password Process</a> from the <a href="http://blogs.technet.com/b/askds/">Ask the Directory Services Team blog</a>.<br />
<br />
Unlike Windows user passwords, machine passwords don't expire; they are entirely client driven - meaning the Windows machine itself decides whether to change the password or not. So, as long as no one messes up the <a href="http://technet.microsoft.com/en-us/library/dd391958">Computer account</a> in AD, as long as the machine doesn't change its machine password, we are good to go.<br />
<br />
Thanks to that article, there are a couple of ways I can accomplish this, both of them through <a href="http://en.wikipedia.org/wiki/Group_Policy">GPOs</a>.<br />
<br />
<ul>
<li>Set the <a href="http://technet.microsoft.com/en-us/library/jj852252">Domain member: Maximum machine account password age</a> rule to 0 (zero).</li>
<li>Set the Netlogon registry value <a href="http://support.microsoft.com/kb/154501">DisablePasswordChange</a> to 1 (one).</li>
</ul>
<br />
If you haven't read it and like knowing nitty-gritty details, I highly recommend reading the <a href="http://blogs.technet.com/b/askds/archive/2009/02/15/test2.aspx">Machine Account Password Process</a> article.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-60662849088276154862013-09-27T00:43:00.000-05:002013-09-28T02:37:35.010-05:00SQL Server 2012 Integration Services and DCOM PermissionsOn my development machine, I noticed I was getting the same DistributedCOM error 28 times every 15 minutes.<br />
<blockquote class="tr_bq">
<b>The application-specific permission settings do not grant Local Activation permission for the COM Server application with CLSID {FDC3723D-1588-4BA3-92D4-42C430735D7D} to the user NT AUTHORITY\NETWORK SERVICE SID (S-1-5-20) from address LocalHost (Using LRPC). This security permission can be modified using the Component Services administrative tool.</b></blockquote>
I'm not sure it is possible for this error to be any more cryptic. Luckily, I know a little about DCOM permissions. Roughly translated, there is a process calling a particular <a href="http://msdn.microsoft.com/en-us/library/ms683835">COM+ server</a> (also known as a component). When that happens, the process fails to create/initialize the component because of a permissions error.<br />
<br />
<h2>
Debugging the Error</h2>
Based on the error, I know a couple of things. I know the process is a Windows service. Only Windows services can run under the <a href="http://msdn.microsoft.com/en-us/library/ms684272">Network Service</a> (also known as "NT Authority\Network Service") user. I also know the <a href="http://en.wikipedia.org/wiki/Globally_unique_identifier">GUID</a> listed is the <a href="http://en.wikipedia.org/wiki/CLSID#Subtypes">CLSID</a> (also known as the Class ID) for the component.<br />
<br />
Now, all COM security is configured from a little utility named <a href="http://msdn.microsoft.com/en-us/library/ms690141">dcomcnfg.exe</a>. More specifically, the permissions I need to deal with are handled under the "DCOM Config" branch of the tree displayed in <b>dcomcnfg</b>.<br />
<blockquote class="tr_bq">
<b>Console Root -> Component Services -> Computers -> My Computer -> DCOM Config</b></blockquote>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-dg06pQUfNLw/UkUJxZvQkXI/AAAAAAAAA1c/jh4FFlRpGv4/s1600/DComCnfg0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="202" src="http://2.bp.blogspot.com/-dg06pQUfNLw/UkUJxZvQkXI/AAAAAAAAA1c/jh4FFlRpGv4/s400/DComCnfg0.png" width="400" /></a></div>
<br />
So, a quick look at the listed components; and the CLSID can't be found. That's okay. Components can be listed in a variety of ways. The CLSID is only used as a last ditch effort if a more readable name is not stored for the component. To find the name for the component, I need to look it up in the registry under <a href="http://msdn.microsoft.com/en-us/library/ms691424">HKCR\CLSID</a>, which gives me something much more useful.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-RhTaOE3vEk4/UkT9l30T76I/AAAAAAAAA00/2Q9spEaTDzs/s1600/CLSID.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="203" src="http://1.bp.blogspot.com/-RhTaOE3vEk4/UkT9l30T76I/AAAAAAAAA00/2Q9spEaTDzs/s400/CLSID.png" width="400" /></a></div>
<br />
Now I know that the COM+ server is named <b>Microsoft.SqlServer.Dts.Server.DtsServer</b>, and I know that this is definitely related to <a href="http://en.wikipedia.org/wiki/Data_Transformation_Services">SQL Server - Data Transformation Services</a> by the name. Switching back to <b>dcomcnfg</b>, the <b>Microsoft.SqlServer.Dts.Server.DtsServer</b> component is not listed either.<br />
<br />
What else can the component be named? The registry key also displays an <a href="http://en.wikipedia.org/wiki/Globally_unique_identifier#Subtypes">AppID</a> GUID in addition to the component name. This represents the name of the <a href="http://blogs.msdn.com/b/jigarme/archive/2007/10/09/what-is-appid.aspx">process</a> that hosts the component. Similarly to a component name, I can look up the application name in the registry under <a href="http://msdn.microsoft.com/en-us/library/aa367566">HKCR\AppID</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-BA678C1W5b0/UkT_AGEhVzI/AAAAAAAAA1A/evbFf39aBnI/s1600/AppID.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="202" src="http://3.bp.blogspot.com/-BA678C1W5b0/UkT_AGEhVzI/AAAAAAAAA1A/evbFf39aBnI/s400/AppID.png" width="400" /></a></div>
<br />
The process listed here is a Windows Service named <b>MsDtsServer110</b>, which is the short name for the <a href="http://msdn.microsoft.com/en-us/library/ms143731.aspx">SQL Server Integration Services 11.0</a> service. Switching back to <b>dcomcnfg</b>, the <b>SQL Server Integration Services 11.0</b> component <i>is</i> listed. Perfect. Now all I have to do is configure it.<br />
<br />
<h2>
Fixing the Permissions</h2>
<div>
The steps listed here are very specific to my error but can easily be adapted to whatever component you need by replacing <b>SQL Server Integration Services 11.0</b> with the appropriate application name, AppID or CLSID and replacing <b>Network Service</b> with the appropriate Windows user.</div>
<div>
<ol>
<li>In <b>dcomcnfg</b>, right-click on <b>SQL Server Integration Services 11.0</b> and click on Properties.</li>
<br />
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-vD1tn209mAU/UkURqFBBhVI/AAAAAAAAA2U/8MkhE_asg5M/s1600/DComCnfg1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="203" src="http://4.bp.blogspot.com/-vD1tn209mAU/UkURqFBBhVI/AAAAAAAAA2U/8MkhE_asg5M/s400/DComCnfg1.png" width="400" /></a></div>
</div>
<br />
<li>Change to the <b>Security</b> tab.</li>
<li>Under <b>Launch and Activation Permissions</b> select <b>Customize</b>.</li>
<br /><div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-UCi8LRtF8cI/UkURTY9gB0I/AAAAAAAAA14/-07mzFhMyvo/s1600/DComCnfg2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="400" src="http://4.bp.blogspot.com/-UCi8LRtF8cI/UkURTY9gB0I/AAAAAAAAA14/-07mzFhMyvo/s400/DComCnfg2.png" width="303" /></a></div>
</div>
<br />
<li>Click [Edit] to display the <b>Launch and Activation Permissions</b> window.</li>
<br /><div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-pfGVmq8L_C8/UkURTZcLtQI/AAAAAAAAA10/PKurw1vY0M8/s1600/DComCnfg3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="400" src="http://3.bp.blogspot.com/-pfGVmq8L_C8/UkURTZcLtQI/AAAAAAAAA10/PKurw1vY0M8/s400/DComCnfg3.png" width="331" /></a></div>
</div>
<br />
<li>Click [Add] to open the <b>Select Users or Groups</b> window.</li>
<br /><div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-fSBo8aEecSo/UkURToQExMI/AAAAAAAAA2M/RxsaBG0HMVk/s1600/DComCnfg4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="216" src="http://2.bp.blogspot.com/-fSBo8aEecSo/UkURToQExMI/AAAAAAAAA2M/RxsaBG0HMVk/s400/DComCnfg4.png" width="400" /></a></div>
</div>
<br />
<li>Enter <b>Network Service</b>.</li>
<li>Click [Check Names].</li>
<li>Click [OK] to close the <b>Select Users or Groups</b> window.</li>
<br /><div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-g2jHKrSmhTA/UkURT9MTfpI/AAAAAAAAA2E/B2k4B3Tj3TQ/s1600/DComCnfg5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="http://3.bp.blogspot.com/-g2jHKrSmhTA/UkURT9MTfpI/AAAAAAAAA2E/B2k4B3Tj3TQ/s400/DComCnfg5.png" width="331" /></a></div>
</div>
<br />
<li>Select <b>NETWORK SERVICE</b> in the <b>Group or user names</b> list.</li>
<li>Check the <b>Local Launch</b> and <b>Local Activation</b> permissions.</li>
<li>Click [OK] to close the <b>Launch and Activation Permissions</b> window.</li>
</ol>
<div>
The error should now be resolved. For me, all I have to do is wait 15 minutes to see if the error is logged again. If your error can be duplicated another way, repeat those steps to see if you are still getting the error.</div>
</div>
<div>
<br /></div>
<h2>
How did I get here?</h2>
<div>
Perhaps more important than all of this is, "why did I get this error in the first place?" The answer to that, in my case, is that I installed SQL Server 2012 and selected <b>Network Service</b> as the logon account for all the Windows services created by the installer. This is contrary to recommended practices, especially since the SQL Server 2012 installer has the ability to configure Windows accounts specifically for use by the Windows services it creates.</div>
<div>
<br /></div>
<div>
The short answer is that <a href="http://idioms.thefreedictionary.com/shoot+oneself+in+the+foot">I shot myself in the foot</a> because I didn't follow recommended security practices for the installation of SQL Server. Still, I would have thought that DCOM permissions would have been automatically configured for these components upon installation.</div>
<div>
<br /></div>
<div>
Regardless, it was relatively easy to fix, as long as I knew what DCOM was and how to deal with it.<br />
<br />
<b>Update (2013-09-28):</b> Found another useful article for <a href="http://technet.microsoft.com/en-us/library/cc751272.aspx">Troubleshooting DCOM</a> and thought I would share.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-67079311219470548032013-09-21T18:52:00.004-05:002013-09-21T18:53:25.794-05:00Encrypted File System on Windows 7 Home PremiumWhile <a href="http://en.wikipedia.org/wiki/Windows_7">Windows 7</a> <a href="http://en.wikipedia.org/wiki/Windows_7_editions#Comparison_chart">Home Premium</a> edition doesn't support <a href="http://en.wikipedia.org/wiki/Encrypting_File_System">EFS</a>, you can get it working in a roundabout way - given you have temporary access to a copy of Windows that does have support for EFS. I found this out while using an external hard drive when passing files between my desktop (Windows Vista Ultimate) and my laptop (Windows 7 Home Premium).<br />
<br />
<ol>
<li>On the machine which does support EFS, go ahead and <a href="http://technet.microsoft.com/en-us/library/cc875821.aspx">set up an encryption certificate</a>.</li>
<li><a href="http://technet.microsoft.com/en-us/library/cc875821.aspx#EEAA">Export the encryption certificate, copy it over to the Windows 7 machine and install it</a>.</li>
<li>Create a folder and mark it as encrypted on the first machine.</li>
<li>Copy the folder onto a USB drive formatted with NTFS.</li>
<li>Finally, copy the folder from the USB drive onto the Windows 7 machine.</li>
</ol>
<div>
Any files created under (or copied to) the encrypted folder will be encrypted, themselves. In addition, this folder can be used as a template for creating additional encrypted folders. So, keeping an empty copy of the folder lying around can be useful.</div>
<br />
<br />
There are a couple caveats to deal with, though.<br />
<br />
<ul>
<li>The hard drives on both machines and the USB drive must be formatted with NTFS.</li>
<li>New folders on the Windows 7 machine cannot be marked as encrypted, unless they are children of folders already encrypted.</li>
<li>Once a folder or file has been encrypted, it cannot be marked as decrypted on the Home Premium machine.</li>
<li>Folders shared on the network cannot be decrypted - regardless of whether the certificate & key are installed on the client machine. This is why a USB drive is required.</li>
</ul>
<div>
I realize this seems a long way to go just to get EFS onto a weaker copy of Windows 7. To be honest, I don't use EFS on my laptop extensively; but the files I keep encrypted, I want them to stay encrypted, regardless of which machine they are stored.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-43400359724951432732013-06-02T03:52:00.003-05:002015-02-20T15:39:52.536-06:00SQL Server 2012 Install Fails on Server Core 2008 R2 VHD - Object reference not set to an instance of an object.<div class="tr_bq">
So, I'm going through the <a href="http://www.amazon.com/Training-Kit-Exam-70-462-Administering/dp/0735666075">Administering Microsoft SQL Server 2012 Databases</a> book for the <a href="http://www.microsoft.com/learning/en/us/exam-70-462.aspx#fbid=RHJfZWXXeyH">70-462 certification exam</a>. The only way, I could quickly get access to <a href="http://technet.microsoft.com/en-us/library/dd184075.aspx">Windows Server Core</a> for the test exercises was to download the <a href="http://www.microsoft.com/en-us/download/details.aspx?id=18348">VHD provided by Microsoft</a>.</div>
<br />
Well, strange thing. It is missing a critical registry key. Without this key, SQL Server fails with a horribly vague error. To make it more fun, while the description tells me to look in a file named summary.txt, there is no file named summary.txt anywhere.<br />
<blockquote>
<pre>The following error occurred:
Object reference not set to an instance of an object.
Error result: -2147467261
Result facility code: 0
Result error code: 16387
Please review the summary.txt log for further details
</pre>
</blockquote>
Slightly more - but also unhelpful - information can be found in the <a href="http://msdn.microsoft.com/en-us/library/ms143702(v=sql.110).aspx">Component Updater log file</a> generated by the installer.<br />
<blockquote class="tr_bq">
<pre>Exception summary:
The following is an exception stack listing the exceptions in outermost to innermost order
Inner exceptions are being indented
Exception type: System.NullReferenceException
Message:
Object reference not set to an instance of an object.
Data:
DisableWatson = true
Stack:
at Microsoft.SqlServer.Configuration.MsiExtension.ArpRegKey.CleanupPatchedProductRegistryInfo()
at Microsoft.SqlServer.Configuration.MsiExtension.SetPatchInstallStateAction.ExecuteAction(String actionId)
at Microsoft.SqlServer.Chainer.Infrastructure.Action.Execute(String actionId, TextWriter errorStream)
at Microsoft.SqlServer.Setup.Chainer.Workflow.ActionInvocation.ExecuteActionHelper(TextWriter statusStream, ISequencedAction actionToRun, ServiceContainer context)</pre>
</blockquote>
<div>
Anyway, after a couple of hours of messing around with it, I find a post on the <a href="http://social.msdn.microsoft.com/Forums/en-US/sqlsetupandupgrade/thread/c588b06e-7002-40ba-bf59-7e7c9decaf23/">Microsoft Forums</a> that finally sheds some light on it. Apparently the <span style="background-color: #cccccc; font-family: Courier New, Courier, monospace;">HKLM\Software\Microsoft\Windows NT\CurrentVersion\Uninstall</span> registry key doesn't exist in the distributed virtual hard drive. Either adding this key or running an installer that creates it seems to fix the problem.<br />
<br />
Hopefully, this will save others some debugging time and effort.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-30934863562480450022013-05-31T17:21:00.002-05:002013-06-13T10:56:37.785-05:00Configuring DEP on Windows Server 2008 R2 from a 32bit NSIS Installer - Revisited<span style="color: #333333;">Thanks to another blog, <a href="http://blogs.msdn.com/b/oldnewthing/">The Old New Thing</a>, I found out there is <a href="http://blogs.msdn.com/b/oldnewthing/archive/2013/03/21/10404021.aspx">another</a> <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa384187(v=vs.85).aspx">way</a> to handle writing to the 64bit Registry from a 32bit program - without the needing to deal with file redirection. Well, almost without the need for it. Starting with Windows Vista, a special alias <span style="background-color: #cccccc; font-family: Courier New, Courier, monospace;">%windir%\Sysnative</span> was added to allow access to the System32 directory even when running a 32bit program.</span><br />
<span style="color: #333333;"><br /></span>
<span style="color: #333333;">Unfortunately, Windows XP and Windows Server 2003 don't have this feature; and since we still work with both of these versions of Windows, I cannot incorporate it into our code. Anyway, since the <a href="http://klonkers.blogspot.com/2012/04/configuring-dep-on-windows-server-2008.html">original post</a> is one of my more popular, I thought I would update the code.</span><br />
<pre>var /GLOBAL NSISRegPath
StrCpy $NSISRegPath "SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
var /GLOBAL EXERegPath
StrCpy $EXERegPath "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
${IF} ${AtLeastWinVista}
WriteRegStr HKLM "$NSISRegPath" "$INSTDIR\program.exe" "DisableNXShowUI"
${IF} ${RunningX64}
ExecWait '$WINDIR\SysNative\reg.exe add "$EXERegPath" /v \
"$INSTDIR\program.exe" /d "DisableNXShowUI"'
${ENDIF}
${ENDIF}
</pre>
<div>
<br /></div>
<b style="color: #333333;">Note:</b><span style="color: #333333;"> Lines that end with a backslash represent long lines that have been wrapped.</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-74814604850561649202013-05-30T19:05:00.001-05:002013-06-04T15:57:50.018-05:00How To Encrypt SQL Server Connections - Part 2In my <a href="http://klonkers.blogspot.com/2013/04/how-to-encrypt-sql-server-connections.html">previous post</a>, I covered the steps necessary to enable and enforce encryption for all connections to Microsoft SQL Server. Now, this was nothing more than a step-by-step of what to do. It covered nothing about why or how important this is. Hopefully, I can impress upon the reader how important it is to encrypt connections. Considering the effort involved is extremely minimal - less than an hour of work - this should be the first step after installing SQL Server.<br />
<h2>
How Vulnerable is your Data?</h2>
<div>
Just to prove how easy it is to get access to the underlying data, I installed <a href="http://www.wireshark.org/">Wireshark</a> on my dev machine (actually, I already had it installed - it's a great tool!), started it up and entered the filter "tds" (all lower case). This shows me all the SQL statements going out of my machine and all the responses that come back. While the responses are still <a href="http://en.wikipedia.org/wiki/Tabular_Data_Stream">TDS encoded</a>, it isn't difficult to parse out the data - especially strings - just by looking at it. This can give me access to a boatload of information.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-wUaOv3ZkpYw/UafIFMem_xI/AAAAAAAAAqk/tanbXtIvVqE/s1600/5-30-2013+4-42-56+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="244" src="http://1.bp.blogspot.com/-wUaOv3ZkpYw/UafIFMem_xI/AAAAAAAAAqk/tanbXtIvVqE/s320/5-30-2013+4-42-56+PM.png" width="320" /></a></div>
<br />
<br />
The only thing SQL Server <b>really tries</b> to protect is SQL authentication. Starting with SQL Server 2005, the authentication process attempts an <a href="http://msdn.microsoft.com/en-us/library/dd358306.aspx">SSL handshake</a> before authentication occurs. For the purposes of this post, I am assuming the client supports SSL authentication and the handshake is successful. Please note that this is very different than <a href="http://support.microsoft.com/kb/968389">Extended Protection for Authentication</a>, which is an additional layer on top of SSL encryption. Also, the encryption described here is limited to authentication. After authentication succeeds, the SSL channel is shut down and the connection reverts to an unencrypted state.<br />
<br />
Anyway, when connecting to a SQL Server that isn't configured to use SSL, the server will search for an appropriate server authentication certificate (with accessible private key and matching the NetBIOS name or FQN ) in the Windows server certificate store and use that. If one is not found, a self-signed certificate is generated on-the-fly and is used specifically to protect the authentication portion of the connection. Any subsequent SQL statements or RPC calls are left unencrypted - and so are the results that are sent back.<br />
<br />
<b>Note:</b> SQL Server actually checks for certificates at startup. If a certificate is added or becomes accessible after startup, SQL Server will not use it. Related, if a certificate is removed or becomes inaccessible after startup, SQL Server gracefully falls back to using a self-signed certificate where necessary.<br />
<h2>
Configuring SQL Server to Require Encryption</h2>
<div>
If you haven't read it yet, please, please, please, read my <a href="http://klonkers.blogspot.com/2013/04/how-to-encrypt-sql-server-connections.html">previous post</a>. Getting SQL Server configured to require encryption is extremely simple. You can even use a self-signed certificate if need be. As long as connections to your SQL Server are unencrypted your data is vulnerable to anyone with a packet sniffer and access to your network.</div>
<h2>
Configuring a Data Source to Require Encryption</h2>
<div>
Configuring a Data Source to require encryption on the client side is also easy. Both the <b><a href="http://msdn.microsoft.com/en-us/library/ms811006.aspx">SQL Server</a></b> driver and the <b><a href="http://msdn.microsoft.com/en-us/sqlserver/ff658532.aspx">SQL Server Native Client</a> </b>driver in the <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms714024(v=vs.85).aspx">ODBC Data Source Administrator</a> provides a checkbox for enabling encryption. On the fourth page of the wizard, simply check the <b>"Use string encryption for data"</b> setting and save the Data Source. All connections using that Data Source will now require encryption and perform client side validation of the server's certificate.</div>
<div>
<br /></div>
<div>
<b>Note</b>: This only tells the client to require encryption. It does not enable encryption, something which must be done on the server.</div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-rPXci6K-cLw/UafeSusDn9I/AAAAAAAAArM/ErtdJtpktXA/s1600/5-30-2013+6-13-15+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="http://3.bp.blogspot.com/-rPXci6K-cLw/UafeSusDn9I/AAAAAAAAArM/ErtdJtpktXA/s320/5-30-2013+6-13-15+PM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
SQL Server driver wizard</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-U7SciDz9AJc/UafeTIXvrlI/AAAAAAAAArQ/gmBeD4R19wI/s1600/5-30-2013+6-12-58+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="220" src="http://4.bp.blogspot.com/-U7SciDz9AJc/UafeTIXvrlI/AAAAAAAAArQ/gmBeD4R19wI/s320/5-30-2013+6-12-58+PM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
SQL Server Native Client driver wizard</div>
<h2>
What Validation Checks Occur on the Client Side?</h2>
<div>
Since validation occurs (I'm assuming) via <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa388208(v=vs.85).aspx">WinVerifyTrust</a>, all the bells and whistles that come with certificate validation in Windows occur. Although, there are a couple of small differences in how the <b>SQL Server</b> driver and the <b>SQL Server Native Client</b> driver handle client side validation. The <b>SQL Server Native Client</b> driver includes more detailed descriptions of any SSL errors, while the <b>SQL Server</b> driver simply returns a generic SSL failure error. In addition, the <b>SQL Server Native Client</b> driver includes a principal name check, which compares the server name in the Data Source (excluding the SQL Server instance name) against the common name in the server's certificate. </div>
<div>
<br /></div>
<div>
For example, if the SQL Server is using a certificate with a FQN but a Data Source only specifies the NetBIOS name, the validation will fail. So, <span style="background-color: #cccccc; font-family: Courier New, Courier, monospace;">sqlserver\myinstance</span> will fail if the server's certificate has a common name of <span style="background-color: #cccccc; font-family: Courier New, Courier, monospace;">sqlserver.domain.com</span>, but <span style="background-color: #cccccc; font-family: Courier New, Courier, monospace;">sqlserver.domain.com\myinstance</span> will succeed. The same goes for specifying the IP address instead of a server name.</div>
<div>
<br /></div>
<div>
Digging a little deeper into the validation check and how WinVerifyTrust works, the certificate must be signed by a trusted root certificate or have intermediary certificates that are signed by a trusted root certificate. The certificate can be purchased from any Certificate Authority, can be created from an internal <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms755466(v=vs.85).aspx">Windows Server Certificate Authority</a>, can be created from an internal <a href="http://www.openssl.org/docs/apps/ca.html">OpenSSL Certificate Authority</a> (as long as the certificate authority roots are distributed to all Windows machines), or even - and this is a little wacky - a self-signed certificate (as long as the certificate is distributed as a trusted certificate - not necessarily trusted root certificate - to all Windows machines).</div>
<div>
<br /></div>
<div>
<i><b>Yes. Even a self-signed certificate will work. As long as the client machines trust the certificate, client validation will pass. If you don't enable encryption on the client side, the certificate doesn't even have to be trusted on the client machines.</b></i></div>
<div>
<br /></div>
<div>
Given that any SQL Server should only be internally accessible and client side validation is not required, there is not really even a reason to purchase an SSL certificate. Any certificate will do, as long as it fits the requirements for SQL Server.</div>
<h2>
Notes</h2>
<h3>
Use Cases</h3>
<div>
For the purposes of this discussion, I have included a list below of all the applicable scenarios relating to client and server encryption settings. Hopefully, this gives an idea of the underlying functionality and answer some common questions.</div>
<ul>
<li>Client does not require encryption and server is configured to use a specific certificate but not require SSL. Both the <b>SQL Server</b> driver and the <b>SQL Server Native Client</b> driver will work without errors. The connection will be unencrypted, although the authentication process will use the server's certificate for encrypting the authentication handshake. Certificate validation is completely skipped on the client side.</li>
</ul>
<ul>
<li>Client does not require encryption and server is configured to require SSL. Both the <b>SQL Server</b> driver and the <b>SQL Server Native Client</b> driver will work without errors. The connection - authentication and otherwise - is encrypted using the server's certificate. Certificate validation is completely skipped on the client side.</li>
</ul>
<ul>
<li>Client requires encryption, but server doesn't have access to a certificate & key. Both the <b>SQL Server</b> driver and the <b>SQL Server Native Client</b> driver will generate SSL errors and abort the connection. Since the client is demanding an SSL connection and the server only has a self-signed certificate it generated on-the-fly, the certificate validation fails.</li>
</ul>
<ul>
<li>Client requires encryption, but server is not configured to use SSL - although it has access to a certificate and key. Both the <b>SQL Server</b> driver and the <b>SQL Server Native Client</b> driver will work without errors (if the certificate passes validation checks on the client side). Since the client is demanding an SSL connection, the server does its best to find and use one. If more than one server authentication certificate and private key are accessible, you have no guarantee which certificate it will use.</li>
</ul>
<ul>
<li>Client requires encryption and server is configured to use SSL but not require it. Both the <b>SQL Server</b> driver and the <b>SQL Server Native Client</b> driver will work without errors (if the certificate passes validation checks on the client side). Since the client is demanding an SSL connection, all interaction is encrypted using the server's certificate. </li>
</ul>
<ul>
<li>Client requires encryption and server is configured to require SSL. Both the <b>SQL Server</b> driver and the <b>SQL Server Native Client</b> driver will work without errors (if the certificate passes validation checks on the client side). Since the client is demanding an SSL connection, all interaction is encrypted using the server's certificate. </li>
</ul>
<div>
<h3>
Client Side Errors</h3>
<div>
During the course of my testing, there are three SSL errors that can occur on the client side. Well, at least, three errors that I found when using the [Test Data Source...] button in the ODBC Data Source Administrator window. There are probably many more. One from the <b>SQL Server</b> driver and two from the <b>SQL Server Native Client</b> driver. I have included screenshots below of each.</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-3-REzbhs9v8/UafYB8GU79I/AAAAAAAAAqw/OIBnlsZ863M/s1600/5-30-2013+4-55-37+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-3-REzbhs9v8/UafYB8GU79I/AAAAAAAAAqw/OIBnlsZ863M/s320/5-30-2013+4-55-37+PM.png" width="310" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Generic SSL error from the SQL Server driver</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-2_GuVG0XSa0/UafYBxqe3hI/AAAAAAAAAq4/V_QZunP9tqQ/s1600/5-30-2013+4-55-50+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://4.bp.blogspot.com/-2_GuVG0XSa0/UafYBxqe3hI/AAAAAAAAAq4/V_QZunP9tqQ/s320/5-30-2013+4-55-50+PM.png" width="310" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Certificate Chain SSL error from the SQL Server Native Client driver</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-uIFTpp7H8DU/UafYB37GaqI/AAAAAAAAAq0/_G9NsWImRxw/s1600/5-30-2013+5-27-28+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-uIFTpp7H8DU/UafYB37GaqI/AAAAAAAAAq0/_G9NsWImRxw/s320/5-30-2013+5-27-28+PM.png" width="310" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Principal Name SSL error from the SQL Server Native Client driver</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-18286081504852535532013-04-19T20:01:00.001-05:002013-04-20T21:05:05.082-05:00How To Encrypt SQL Server Connections<h2>
Open the Logical Certificate Store for the Local Machine</h2>
<ol>
<li>Start the Microsoft Management Console (mmc.exe)</li>
<li>Under the File menu select <b>Add/Remove Snap-in…</b> to launch the Add or Remove Snap-ins window.</li>
<li>Select <b>Certificates</b> from the list of Available Snap-ins.</li>
<li>Click [Add >] to launch the Certificates snap-in configuration window.</li>
<li>Select <b>Computer account</b></li>
<li>Click [Next]</li>
<li>Select <b>Local computer</b></li>
<li>Click [Finish] to close the Certificates snap-in configuration window.</li>
<li>Click [OK] to close the Add or Remove Snap-ins window.</li>
</ol>
<b></b> <br />
<h2>
Create a Certificate Request</h2>
<ol>
<li>In the Microsoft Management Console, select <b>Certificates (Local Computer)</b> on the left side of the window. This will display a list of certificate categories.</li>
<li>Right-click on the <b>Personal</b> on the right side of the window.</li>
<li>Click on <b>Create custom request</b> under <b>Add Tasks</b> -> <b>Advanced Operations</b> to launch the Certificate Enrollment wizard.</li>
<li>Click [Next] to go to the Certificate request page</li>
<li>From the <b>Template</b> dropdown select <b>(No template) Legacy key</b> and leave the <b>Request format</b> as <b>PKCS #10</b>.</li>
<li>Click [Next] to go to the Certificate information page.</li>
<li>Expand the request by clicking on the <a href="http://lh5.ggpht.com/-AgaI9MjluOw/UXHo0B_HJoI/AAAAAAAAAoQ/sLVaPEyx_og/s1600-h/clip_image004%25255B3%25255D.jpg"><img alt="clip_image004" border="0" height="19" src="http://lh3.ggpht.com/-Nhq6IY2M5pI/UXHo0njfR5I/AAAAAAAAAoY/gMbJ1cA3nB0/clip_image004_thumb.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="clip_image004" width="19" /></a> button on the right side of the window.</li>
<li>Click [Properties] to launch the Certificate Properties window.</li>
<li>On the <b>General</b> tab, in the <b>Friendly Name</b> field, enter <b>SSL Certificate for SQL Server</b>. The friendly name can actually be anything, but it should be easily distinguishable as the certificate for the SQL Server.</li>
<li>On the <b>Subject</b> tab, add the <b>Common Name</b> attribute with the actual name of the server. If the server is part of a Windows domain, it must be the fully qualified name of the server including the domain. If the server is not part of a Windows domain, it must be the NetBios name of the server.</li>
<li>Also on the <b>Subject</b> tab, add any other attributes required by your Certificate Authority</li>
<li>On the <b>Private Key</b> tab, change the <b>Key Type</b> to <b>Exchange</b>.</li>
<li>Expand the <b>Key options</b> group on the <b>Private Key</b> tab and change the <b>Key size</b> to 2048.</li>
<li>Expand the <b>Key permissions</b> group on the <b>Private Key</b> tab, check <b>Use custom permissions.</b></li>
<li>Click [Set permissions] to open the Permissions window.</li>
<li>From here add the start up account for SQL Server service. This is the “<b>Log on as”</b> Windows account used by the SQL Server service. If necessary, this can be configured later.</li>
<li>Click [OK] to close the Permissions window.</li>
<li>Click [OK] to close the Certificate Properties window.</li>
<li>Click [Next] in the Certificate Enrollment wizard to go to the Export page of the wizard.</li>
<li>Enter (or browse for) a File Name for the certificate request export.</li>
<li>Click [Finish].</li>
</ol>
Once complete, a Certificate Request file will be generated and can be turned into a Certificate by any certificate authority.<br />
<br />
<h2>
Generate Signed Certificate</h2>
<div>
<<insert magic here>></div>
<div>
<br /></div>
<div>
I leave it up to the reader to decide how to generate a signed certificate. Whether using a 3rd party certificate authority, a Windows certificate authority in Active Directory, or generating a self-signed certificate, all will work. And, YES, a self-signed certificate will work - at least, at this stage in the game. While the SQL Server can require encrypted connections, it is up to the client to decide whether certificate validations occur. This will be covered later in Part 2.</div>
<br />
<b></b> <br />
<h2>
Import the Signed Certificate</h2>
<ol>
<li>In the Microsoft Management Console, select <b>Certificates (Local Computer)</b> on the left side of the window.</li>
<li>Right-click on the<b> Personal</b> on the right side of the window.</li>
<li>Click on <b>Import</b> under <b>All Tasks</b> to launch the Certificate Import Wizard.</li>
<li>Click [Next].</li>
<li>Enter (or browse for) the signed certificate file generated by the certificate authority.</li>
<li>Click [Next].</li>
<li>Click [Next].</li>
<li>Click [Finish] to close the Certificate Import Wizard.</li>
</ol>
<h2>
Configure SQL Server to Use Encrypted Connections</h2>
<ol>
<li>Start the <b>SQL Server Configuration Manager</b>.</li>
<li>Expand <b>SQL Server Network Configuration</b>.</li>
<li>Right-click on <b>Protocols for MSSQLSERVER</b>. If SQL Server is installed as an instance, MSSQLSERVER will actually be the name of the instance. </li>
<li>From the context menu, click <b>Properties</b> to launch the Protocols for MSSQLSERVER Properties window.</li>
<li>On the <b>Flags</b> tab, select <b>Force Encryption</b> and change the value to <b>Yes</b>.</li>
<li>On the <b>Certificate</b> tab, select the <b>SSL Certificate for SQL Server</b> certificate from the dropdown. The certificates listed here will be listed by the <b>Friendly Name</b> on the certificate. If not specified, the <b>Common Name</b> will be listed instead.</li>
<li>Click [OK] to close the Protocols for MSSQLSERVER Properties window.</li>
<li>In the SQL Server Configuration Manager window, select <b>SQL Server Services</b>.</li>
<li>Right-click on <b>SQL Server (MSSQLSERVER)</b> on the right side of the window.</li>
<li>From the context menu, click <b>Restart</b>.</li>
</ol>
<br />
<h2>
Notes</h2>
<div>
<br /></div>
<h3>
Minimum SSL Certificate Requirements</h3>
In some cases, the certificate may not appear in the SQL Server Configuration Manager window. Below are the absolute minimum requirements for a certificate to show in the window and for it to work with SQL Server. <br />
<ul>
<li>The Template used must be <b>(No template) Legacy key</b>. This allows the <b>Key Type</b> to be changed.</li>
<li>Private key must have a <b>Key Type</b> of <b>Exchange</b>. </li>
<li>The <b>Common Name</b> (or <b>Issued To</b>) attribute must be the same as the server name. If part of a domain, this will be the fully qualified domain name of the machine. If not part of a domain, it will simply be the NetBios name of the machine.</li>
<li>The Enhanced Key Usage for the certificate must allow for <b>Server Authentication (1.3.6.1.5.5.7.3.1)</b>.</li>
<li>The certificate & private key must be stored in the logical certificate store for the local computer.</li>
<li>The private key must be accessible to the <b>Log On as</b> Windows account for the SQL Server service. Even if inaccessible, the certificate will display, but the service will fail to start. </li>
</ul>
<div>
<br /></div>
<h3>
SQL Server Fails to Restart</h3>
If permissions are not properly configured, the exception <b>0x8009030d</b> may occur during SQL Server startup and be logged in the SQL Server ERRORLOG file. Because SQL Server has been configured to require encrypted connections, this will prevent the SQL Server service to start. The full text of the error will be similar to the following:<br />
<blockquote class="tr_bq">
<span style="font-family: Times, Times New Roman, serif;">The server could not load the certificate it needs to initiate an SSL connection. It returned the following error: 0x8009030d. Check certificates to make sure they are valid.</span></blockquote>
To resolve the issue, modify the permissions for the certificates private key as covered in <a href="http://www.blogger.com/blogger.g?blogID=13350047#_Configure_Private_Key">Configure Private Key Permissions</a>. Alternately, reconfigure the SQL Server to use unencrypted connections as covered in <a href="http://www.blogger.com/blogger.g?blogID=13350047#_Configure_SQL_Server">Configure SQL Server to Use Unencrypted Connections</a>.<br />
<br />
<h3>
Configure Private Key Permissions</h3>
If the SQL Server fails to start, check the permissions to the certificate’s private key. <br />
<ol>
<li>In the Microsoft Management Console, select <b>Certificates (Local Computer)</b> on the left side of the window.</li>
<li>Double-click on the <b>Personal</b> category on the right side of the window.</li>
<li>Double-click on <b>Certificates</b> on the right side of the window.</li>
<li>Right-click on the certificate and click <b>Manage Private Key…</b>under <b>All Tasks</b>. This will open the Permissions window for the certificate’s private key.</li>
<li>From here add the start up account for SQL Server service. This is the “<b>Log on as”</b> Windows account used by the SQL Server service.</li>
<li>Click [OK] to close the permissions window.</li>
</ol>
<div>
<br /></div>
<h3>
Configure SQL Server to Use Unencrypted Connections</h3>
If all else fails, reverting to unencrypted connections may be the only way to restore access to the SQL Server. <br />
<ol>
<li>Start the <b>SQL Server Configuration Manager</b>.</li>
<li>Expand <b>SQL Server Network Configuration</b>.</li>
<li>Right-click on <b>Protocols for MSSQLSERVER</b>. If SQL Server is installed as an instance, MSSQLSERVER will actually be the name of the instance. </li>
<li>From the context menu, click <b>Properties</b> to launch the Protocols for MSSQLSERVER Properties window.</li>
<li>On the <b>Flags</b> tab, select <b>Force Encryption</b> and change the value to <b>No</b>.</li>
<li>On the <b>Certificate</b> tab, click [Clear].</li>
<li>Click [OK] to close the Protocols for MSSQLSERVER Properties window.</li>
<li>In the SQL Server Configuration Manager window, select <b>SQL Server Services</b>.</li>
<li>Right-click on <b>SQL Server (MSSQLSERVER)</b> on the right side of the window.</li>
<li>From the context menu, click <b>Restart</b>.</li>
</ol>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-62433054526794745222012-07-06T14:03:00.000-05:002012-07-06T21:21:06.096-05:00Formatting XML using MSXMLHere's another useful bit of code used to generate formatted XML. This particular code - in C++ form - will eventually be incorporated into the Platypus API Service, when logging API calls is enabled.<br />
<br />
<span style="font-family: 'Courier New'; font-size: 10pt;"><span style="color: blue;">Function</span> PrettyPrintXML(strXML)<br /><br /> <span style="color: blue;">Dim</span> objReader, objWriter<br /> <span style="color: blue;">Set</span> objReader = <span style="color: blue;">CreateObject</span>(<span style="color: grey;">"MSXML2.SAXXMLReader.6.0"</span>)<br /> <span style="color: blue;">Set</span> objWriter = <span style="color: blue;">CreateObject</span>(<span style="color: grey;">"MSXML2.MXXMLWriter.6.0"</span>)<br /><br /> objWriter.indent = <span style="color: blue;">True</span><br /> objWriter.standalone = <span style="color: blue;">False</span><br /> objWriter.omitXMLDeclaration = <span style="color: blue;">False</span><br /> objWriter.encoding = <span style="color: grey;">"utf-8"</span><br /><br /> <span style="color: blue;">Set</span> objReader.contentHandler = objWriter<br /> <span style="color: blue;">Set</span> objReader.dtdHandler = objWriter<br /> <span style="color: blue;">Set</span> objReader.errorHandler = objWriter<br /><br /> objReader.putProperty _<br /> <span style="color: grey;">"http://xml.org/sax/properties/declaration-handler"</span>, _<br /> objWriter<br /> objReader.putProperty _<br /> <span style="color: grey;">"http://xml.org/sax/properties/lexical-handler"</span>, _<br /> objWriter<br /><br /> objReader.parse strXML<br /><br /> PrettyPrintXML = objWriter.output<br /><br /><span style="color: blue;">End</span> <span style="color: blue;">Function</span></span><br />
<span style="background-color: white;"><br /></span><br />
<span style="background-color: white;">The <a href="http://stackoverflow.com/questions/1118576/how-can-i-pretty-print-xml-source-using-vb6-and-msxml">credit</a> for this actually goes to </span><a href="http://stackoverflow.com/users/23368/daniel-rikowski" style="background-color: white;">Daniel Rikowski</a> on <a href="http://stackoverflow.com/">StackOverflow</a>. All I did was convert it into usable VBScript.<br />
<br class="Apple-interchange-newline" />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-24199015156790032862012-05-09T23:01:00.000-05:002012-05-10T10:44:22.641-05:00SQL Challenge - Part 1 - How to Find Contact Email Addresses in Platypus That May Cause an SMTP 550 Error.Occasionally, if I am very lucky, someone will confront me with what I call the "SQL Challenge". Way back in the day of the early 2000's, one of my coworkers and I would try to come up with ways to stretch our <a href="http://en.wikipedia.org/wiki/SQL">SQL</a> knowledge. Thanks to the "SQL Challenge", I am now capable of some fun acrobatics using just a little SQL.<br />
<br />
The rules are fairly simple, once you have the actual challenge. The SQL must be encapsulated into a single SQL statment - be that select, delete, insert or update. It can have all the <a href="http://en.wikipedia.org/wiki/Join_(SQL)">joins</a>, <a href="http://en.wikipedia.org/wiki/SQL#Subqueries">subclauses</a>, <a href="http://www.sqlteam.com/article/using-derived-tables-to-calculate-aggregate-values">derived tables</a>, and <a href="http://msdn.microsoft.com/en-us/library/aa213245(v=sql.80).aspx">whatever else</a> SQL provides, as long as it is included in a single statement. If inserting, updating or deleting, you are allowed a separate SQL statement for each table, but that is the only exception to the one statement rule. So, no cursors or loops. You get a bonuses for using ANSI SQL syntax and for how quickly you finish.<br />
<br />
Today, I got one of those challenges. Let's start with the givens.<br />
<br />
1. We have one or more email addresses stored in customer.email.<br />
2. These emails can be comma delmited or semicolon delimited.<br />
3. There may be spaces embedded before or after commas/semicolons.<br />
4. The emails may be hosted internally or by a 3rd party provider, or a combination of the two.<br />
5. A list of domains is stored in domain_item.domain. These domains are hosted internally.<br />
6. A list of email addresses is stored in email_data.emailaddr. These emails are hosted internally.<br />
7. When sending email messages to the email addresses stored on customer.email, if one of the email addresses is on a hosted domain but the email address is not in the list of hosted emails, the SMTP server will return a <a href="http://www.gettingemaildelivered.com/what-those-smtp-error-codes-mean-and-why-you-should-care">550 (mailbox not found) error</a>.<br />
<br />
Now, the challenge. Given all of the above, we want to find a list of customers with email addresses on customer.email that will generate a 550. This means we want to find a list of email addresses attached to a hosted domain but are not a hosted email address. After a little less than an hour, I made this...<br />
<br />
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: blue; font-family: Consolas;">select</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* The
unique customer id */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">id</span><span style="color: grey;">,</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* The
delimited list of contact email addresses */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* A
hosted domain matching one of the email addresses */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: teal;">domain_item</span><span style="color: grey;">.</span><span style="color: teal;">domain</span><span style="color: grey;">,</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* The
number of email addresses in customer.email */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: magenta;">len</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">)</span> <span style="color: grey;">-</span> <span style="color: magenta;">len</span><span style="color: grey;">(</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span> <span style="color: red;">'@'</span><span style="color: grey;">,</span> <span style="color: red;">''</span><span style="color: grey;">))</span> <span style="color: blue;">as</span> <span style="color: teal;">email_count</span><span style="color: grey;">,</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* The
number of emails that match the hosted domain */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: grey; font-family: Consolas;">(</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: magenta;">len</span><span style="color: grey;">(</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: red;">';'</span><span style="color: grey;">+</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span><span style="color: red;">' '</span><span style="color: grey;">,</span><span style="color: red;">''</span><span style="color: grey;">)+</span><span style="color: red;">';'</span><span style="color: grey;">,</span><span style="color: red;">','</span><span style="color: grey;">,</span> <span style="color: red;">';'</span><span style="color: grey;">))</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: grey;">-</span> <span style="color: magenta;">len</span><span style="color: grey;">(</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: red;">';'</span><span style="color: grey;">+</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span><span style="color: red;">' '</span><span style="color: grey;">,</span><span style="color: red;">''</span><span style="color: grey;">)+</span><span style="color: red;">';'</span><span style="color: grey;">,</span><span style="color: red;">','</span><span style="color: grey;">,</span> <span style="color: red;">';'</span><span style="color: grey;">),</span> <span style="color: red;">'@'</span><span style="color: grey;">+</span><span style="color: teal;">domain_item</span><span style="color: grey;">.</span><span style="color: teal;">domain</span><span style="color: grey;">+</span><span style="color: red;">';'</span><span style="color: grey;">,</span><span style="color: red;">''</span><span style="color: grey;">))</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: grey; font-family: Consolas;">)</span><span style="font-family: Consolas;"> <span style="color: grey;">/</span> <span style="color: magenta;">len</span><span style="color: grey;">(</span><span style="color: red;">'@'</span> <span style="color: grey;">+</span> <span style="color: teal;">domain_item</span><span style="color: grey;">.</span><span style="color: teal;">domain</span> <span style="color: grey;">+</span> <span style="color: red;">';'</span><span style="color: grey;">)</span> <span style="color: blue;">as</span> <span style="color: teal;">domain_count</span><span style="color: grey;">,</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* The
number of hosted email addresses that match the hosted domain */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: grey; font-family: Consolas;">(</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">select</span> <span style="color: magenta;">count</span><span style="color: grey;">(*)</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">from</span> <span style="color: teal;">email_data</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">where</span> <span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">id</span> <span style="color: grey;">=</span> <span style="color: teal;">email_data</span><span style="color: grey;">.</span><span style="color: teal;">d_custid</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: grey;">and</span> <span style="color: red;">';'</span><span style="color: grey;">+</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span><span style="color: red;">' '</span><span style="color: grey;">,</span><span style="color: red;">''</span><span style="color: grey;">),</span><span style="color: red;">','</span><span style="color: grey;">,</span><span style="color: red;">';'</span><span style="color: grey;">)+</span><span style="color: red;">';'</span> <span style="color: grey;">like</span> <span style="color: red;">'%;'</span><span style="color: grey;">+</span><span style="color: teal;">email_data</span><span style="color: grey;">.</span><span style="color: teal;">emailaddr</span><span style="color: grey;">+</span><span style="color: red;">';%'</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: grey;">and</span> <span style="color: teal;">email_data</span><span style="color: grey;">.</span><span style="color: teal;">emailaddr</span> <span style="color: grey;">+</span> <span style="color: red;">';'</span> <span style="color: grey;">like</span> <span style="color: red;">'%@'</span> <span style="color: grey;">+</span> <span style="color: teal;">domain_item</span><span style="color: grey;">.</span><span style="color: teal;">domain</span> <span style="color: grey;">+</span> <span style="color: red;">';'</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: grey; font-family: Consolas;">)</span><span style="font-family: Consolas;"> <span style="color: blue;">as</span> <span style="color: teal;">match_count</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">from</span> <span style="color: teal;">customer</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: grey;">inner</span> <span style="color: grey;">join</span> <span style="color: teal;">domain_item</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">on</span> <span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: red;">';'</span><span style="color: grey;">+</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span><span style="color: red;">' '</span><span style="color: grey;">,</span><span style="color: red;">''</span><span style="color: grey;">)+</span><span style="color: red;">';'</span><span style="color: grey;">,</span><span style="color: red;">','</span><span style="color: grey;">,</span><span style="color: red;">';'</span><span style="color: grey;">)</span> <span style="color: grey;">like</span> <span style="color: red;">'%@'</span><span style="color: grey;">+</span><span style="color: teal;">domain_item</span><span style="color: grey;">.</span><span style="color: teal;">domain</span><span style="color: grey;">+</span><span style="color: red;">';%'</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* Strip
the hosted domain from the delimited list */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/*
Comparing the difference divided by the length of the hosted domain name */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* This
will let us know how many emails _should_ be hosted for this domain */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">where</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: grey; font-family: Consolas;">(</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: magenta;">len</span><span style="color: grey;">(</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: red;">';'</span><span style="color: grey;">+</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span><span style="color: red;">' '</span><span style="color: grey;">,</span><span style="color: red;">''</span><span style="color: grey;">)+</span><span style="color: red;">';'</span><span style="color: grey;">,</span><span style="color: red;">','</span><span style="color: grey;">,</span><span style="color: red;">';'</span><span style="color: grey;">))</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: grey;">-</span> <span style="color: magenta;">len</span><span style="color: grey;">(</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: red;">';'</span><span style="color: grey;">+</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span><span style="color: red;">' '</span><span style="color: grey;">,</span><span style="color: red;">''</span><span style="color: grey;">)+</span><span style="color: red;">';'</span><span style="color: grey;">,</span><span style="color: red;">','</span><span style="color: grey;">,</span><span style="color: red;">';'</span><span style="color: grey;">),</span> <span style="color: red;">'@'</span><span style="color: grey;">+</span><span style="color: teal;">domain_item</span><span style="color: grey;">.</span><span style="color: teal;">domain</span><span style="color: grey;">+</span><span style="color: red;">';'</span><span style="color: grey;">,</span> <span style="color: red;">''</span><span style="color: grey;">))</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: grey; font-family: Consolas;">)</span><span style="font-family: Consolas;"> <span style="color: grey;">/</span> <span style="color: magenta;">len</span><span style="color: grey;">(</span><span style="color: red;">'@'</span><span style="color: grey;">+</span><span style="color: teal;">domain_item</span><span style="color: grey;">.</span><span style="color: teal;">domain</span><span style="color: grey;">+</span><span style="color: red;">';'</span><span style="color: grey;">)</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/*
Compare the _should_ total against the _actual_ total */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* If
they don't match exactly, include the customer in the result */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: grey; font-family: Consolas;"><></span><span style="color: blue; font-family: Consolas;"> </span><span style="color: grey; font-family: Consolas;">(</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* Find
the number of hosted email addresses for this customer */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* That
match one of the email addresses on the delimited list */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: green; font-family: Consolas;">/* This
will let us know how many emails are _actually_ hosted for this domain */</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">select</span> <span style="color: magenta;">count</span><span style="color: grey;">(*)</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">from</span> <span style="color: teal;">email_data</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: blue;">where</span> <span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">id</span> <span style="color: grey;">=</span> <span style="color: teal;">email_data</span><span style="color: grey;">.</span><span style="color: teal;">d_custid</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: grey;">and</span> <span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: red;">';'</span><span style="color: grey;">+</span><span style="color: magenta;">replace</span><span style="color: grey;">(</span><span style="color: teal;">customer</span><span style="color: grey;">.</span><span style="color: teal;">email</span><span style="color: grey;">,</span><span style="color: red;">' '</span><span style="color: grey;">,</span><span style="color: red;">''</span><span style="color: grey;">)+</span><span style="color: red;">';'</span><span style="color: grey;">,</span><span style="color: red;">','</span><span style="color: grey;">,</span><span style="color: red;">';'</span><span style="color: grey;">)</span> <span style="color: grey;">like</span> <span style="color: red;">'%;'</span><span style="color: grey;">+</span><span style="color: teal;">email_data</span><span style="color: grey;">.</span><span style="color: teal;">emailaddr</span><span style="color: grey;">+</span><span style="color: red;">';%'</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas;"><span style="font-size: xx-small;"> <span style="color: grey;">and</span> <span style="color: teal;">email_data</span><span style="color: grey;">.</span><span style="color: teal;">emailaddr</span><span style="color: grey;">+</span><span style="color: red;">';'</span> <span style="color: grey;">like</span> <span style="color: red;">'%@'</span><span style="color: grey;">+</span><span style="color: teal;">domain_item</span><span style="color: grey;">.</span><span style="color: teal;">domain</span><span style="color: grey;">+</span><span style="color: red;">';'</span><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: grey; font-family: Consolas;">)</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-size: xx-small;"><span style="color: blue; font-family: Consolas;">go</span><span style="font-family: Consolas;"><o:p></o:p></span></span></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<span style="font-family: Consolas; font-size: xx-small;"><br /></span></div>
<br />
<span style="font-size: xx-small;"><br /></span><br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-3322036173961923422012-05-06T01:28:00.002-05:002012-07-06T15:40:01.519-05:00Base64 Encoding using MSXML<br />
At the time we were developing the base64 encoder - covered in my <a href="http://klonkers.blogspot.com/2012/05/base64-encoding-in-platypus.html">last post</a>, there already existed a quick and dirty way to perform base64 encoding/decoding through <a href="http://en.wikipedia.org/wiki/MSXML">MSXML</a>. Even though we have decided not to pursue this for any Platypus development, it might benefit someone. Here are examples for using MSXML for base64 encoding/decoding from within <a href="http://en.wikipedia.org/wiki/VBScript">VBScript</a>.<br />
<br />
<span style="font-family: 'Courier New'; font-size: 10pt;"> <span style="color: blue;">Function</span> Base64Encode (strData)<br /> <span style="color: blue;">Set</span> objDocument = <span style="color: blue;">CreateObject</span>(<span style="color: grey;">"MSXML2.DOMDocument"</span>)<br /> <span style="color: blue;">Set</span> objNode = objDocument.createElement(<span style="color: grey;">"document"</span>)<br /> objNode.dataType = <span style="color: grey;">"bin.base64"</span><br /> objNode.nodeTypedValue = strData<br /> Base64Encode = objNode.text<br /> <span style="color: blue;">End</span> <span style="color: blue;">Function</span><br /> <br /> <span style="color: blue;">Function</span> Base64Decode (strData)<br /> <span style="color: blue;">Set</span> objDocument = <span style="color: blue;">CreateObject</span>(<span style="color: grey;">"MSXML2.DOMDocument"</span>)<br /> <span style="color: blue;">Set</span> objNode = objDocument.createElement(<span style="color: grey;">"document"</span>)<br /> objNode.dataType = <span style="color: grey;">"bin.base64"</span><br /> objNode.text = strData<br /> Base64Decode = objNode.nodeTypedValue<br /> <span style="color: blue;">End</span> <span style="color: blue;">Function</span></span><br />
<span style="color: blue; font-family: 'Courier New'; font-size: x-small;"><br /></span><br />
This is covered in more detail in Microsoft's Knowledge Base Article named "<a href="http://support.microsoft.com/kb/254388">How To Create XML Documents with Binary Data in Visual Basic</a>", along with examples for hex encoding and date encoding (<a href="http://en.wikipedia.org/wiki/ISO_8601">ISO-8601</a>).Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-42491993086933732722012-05-05T16:21:00.003-05:002012-05-06T16:33:38.133-05:00Base64 Encoding in Platypus<br />
<a href="http://en.wikipedia.org/wiki/Base64">Base64</a> encoding was originally designed for transmitting binary data over SMTP. When email servers were first created, the SMTP protocol restricted the allowed characters to the first 7bits of ASCII's 8bit character set. Among other things, this prevented binary files from being sent over email.<br />
<br />
Then came <a href="http://en.wikipedia.org/wiki/MIME">MIME</a> and with it, base64 encoding, which converted binary files into readable text suitable for sending over email. With base64, for every 3 bytes of binary data input there are 4 bytes of encoded text returned. Compared with <a href="http://en.wikipedia.org/wiki/Base16">hex (base16) encoding</a>, the other dominant encoding mechanism at the time, base64 encoding is much more efficient in terms of storage by lowering the amount of space needed for attachments from 2:1 (for hex) to 4:3 (for base64). Since its creation, base64 encoding has been included in a variety of internet protocols, including <a href="http://en.wikipedia.org/wiki/SMTP_Authentication">SMTP authentication</a>, <a href="http://en.wikipedia.org/wiki/Basic_access_authentication">HTTP authentication</a>, <a href="http://www.xml.com/pub/a/2003/02/26/binaryxml.html">XML</a> and is used in various subsystems of the Platypus Billing System.<br />
<br />
While <a href="http://msdn.microsoft.com/en-us/vfoxpro/bb190225">Visual FoxPro</a> - the base language for the Platypus Billing System - includes features for encoding and decoding using base64 through <a href="http://msdn.microsoft.com/en-us/library/k0yb2181(v=vs.80).aspx">STRCONV()</a>, that function does not follow the line length requirement in the <a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a> specification, which limits encoded lines to a maximum of 76 characters. For example, if data were encoded into 100 characters, two lines of encoded data would result. The first line 76 characters, followed by CRLF and then the remaining 24 characters.<br />
<br />
At first, this limitation was not a problem. We used 3rd party ActiveX/COM libraries, named EncodeX and SmtpX from Mabry Software, for encoding email attachments and sending emails, respectively. The other use of base64 within Platypus - our own attachment feature first included in Platypus v3 - did not have to interact with any external systems, so RFC 2045 compliance was not a requirement.<br />
<br />
Eventually, we began work on creating a shared library that could wrap all our SMTP functionality for Platypus v5. Up until this point, there were separate classes and libraries for the Platypus client and API. For one, the Platypus client used ActiveX forms of the libraries, while the Platypus API used the COM forms. Of course, this made maintaining that code doubly difficult and it was prone to inconsistent behavior between the Platypus client and API. Because of that inconsistency, limitations in Visual FoxPro, and compatibility problems, we dropped the ActiveX form of SmtpX and completely dropped the EncodeX libraries.<br />
<br />
Unfortunately, because FoxPro's STRCONV() function did not strictly follow MIME, sending attachments encoded using this function would often generate errors. The strange thing was that these errors were not universal across all mail servers. Some were more strict than others. Anyway, to move forward, we decided to develop our own library for base64 encoding.<br />
<br />
This was my first C++ project with Platypus. Up until this point, my development experience - excluding school - was limited to Visual FoxPro, Visual Basic, and SQL. After an excessive amount of research, we found a decent example in the public domain which performed encoding quickly enough and adapted it into a COM library using Visual C++ 6.0. That library has been in use since that time for a majority of Platypus v4 and all of Platypus v5 and v6. Not bad for a piece of of code 10 years old. With the release of Platypus v7, that COM library has been phased out in favor of the <a href="http://www.afterlogic.com/mailbee/smtp">Mailbee SMTP COM library</a>, which handles encoding internally; but the old base64 COM library is still included in our installation sets as part of a fallback feature.<br />
<br />
The original C++ source for the encoder has been phased out of our other components, as well; being replaced with a much improved library. This new library takes advantage of <a href="http://msdn.microsoft.com/en-us/library/8ef0s5kh(v=vs.110).aspx">Microsoft's SecureCRT (secure C runtime)</a> guidelines to prevent buffer overflows, now includes an efficient decoder, and has been fuzz tested to ensure stability. It is currently in use within the updated Mailpopper for re-encoding email attachments that have been decoded by the <a href="http://www.afterlogic.com/mailbee/pop3">Mailbee POP3 COM library</a>, which pulls emails into the Helpdesk features in Platypus.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-40203751606662815702012-04-30T22:18:00.000-05:002013-06-13T11:05:50.790-05:00Configuring DEP on Windows Server 2008 R2 from a 32bit NSIS InstallerIf the title is hard to understand, let me just shorten it to this. The woes of compatibility testing!<br />
<br />
Included with the Platypus Billing System is a number of 3rd party ActiveX libraries. Most of the time, these libraries are wondrous things. Unfortunately, one, in particular, has a problem with Windows <a href="http://en.wikipedia.org/wiki/Data_Execution_Prevention">DEP</a>.<br />
<br />
Now, upon installation of the Platypus client, we can get around this by configuring the Application Compatibility settings of our executable to bypass DEP. So, whenever the exe is launched, the OS will not trap DEP problems for our process. We do all of this by simply writing to the appropriate location in the registry during the installation process.<br />
<br />
<pre>
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
</pre>
All the way from Windows XP up to Windows Server 2008, we simply had to write to the registry. It didn't even matter whether the OS is x86 or x64. It has just worked.<br />
<br />
Anyway, one of the more ingenious and infamous features from Windows Vista is redirection. You see, whenever a 32bit application writes to <span style="font-family: Consolas; font-size: 10pt; line-height: 115%;">HKEY_LOCAL_MACHINE </span>in the registry on 64bit Windows, it is actually writing to <span style="font-family: Consolas; font-size: 10pt; line-height: 115%;">HKEY_LOCAL_MACHINE\Software\Wow6432Node. </span>So, whenever our software was installed, because the installation set is a 32bit application itself, when it writes to the registry, it is actually writing to the 32bit subset of the registry. This includes those pesky Application Compatibility settings I mentioned. Up until the latest version of Windows Server, the OS didn't care whether you configure the compatibility settings in the 32bit or 64bit registry. It checked both when the process started. Here's an example of code we used for configuring DEP*.<br />
<div>
<pre>
!include LogicLib.nsh
!include WinVer.nsh
var /GLOBAL NSISRegPath
StrCpy $NSISRegPath "SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
${IF} ${AtLeastWinXP}
WriteRegStr HKLM "$NSISRegPath" "$INSTDIR\program.exe" "DisableNXShowUI"
${ENDIF}
</pre>
<br /></div>
<span style="line-height: 19px;">Starting with Windows Server 2008 R2, Application Compatibility settings in the 32bit registry now appear to be ignored. Meaning the Platypus client will now crash whenever our troublesome ActiveX library rears its head, because our installation set can't get to the 64bit registry. Not easily, anyway.</span><br />
<br />
<span style="line-height: 19px;">To get around this problem, the creators of </span><a href="http://nsis.sourceforge.net/Main_Page" style="line-height: 19px;">NSIS</a><span style="line-height: 19px;"> - who provide us with the software for making installation sets - were kind enough to </span><a href="http://nsis.sourceforge.net/Include/x64.nsh" style="line-height: 19px;">take advantage</a><span style="line-height: 19px;"> of </span><a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms684139(v=vs.85).aspx" style="line-height: 19px;">some</a><span style="line-height: 19px;"> </span><a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa365744(v=vs.85).aspx" style="line-height: 19px;">features</a><span style="line-height: 19px;"> in 64bit Windows that allows us to get around redirection. Mostly.</span><br />
<span style="line-height: 19px;"><br /></span><span style="line-height: 19px;">Unfortunately, whenever redirection is disabled, it only changes file redirection - not registry redirection. Since our installation set is writing directly to the registry, disabling file redirection doesn't help us. So, we have to find a way to write to the 64bit registry through file redirection. This leads us to <a href="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/reg.mspx?mfr=true">reg.exe</a> - a nifty little utility that came with Windows XP that allows the registry to be accessed from the command line. Since 64bit Windows has a 32bit reg.exe and a 64bit reg.exe, disabling file redirection should allow us to call the 64bit copy directly, which doesn't have that pesky 32bit registry limitation.</span><br />
<span style="line-height: 19px;"><br /></span><span style="line-height: 19px;">All we need to do is to check for 64bit Windows, disable file redirect, run reg.exe and then reenable file redirection. </span><span style="line-height: 19px;">That gives us code that looks something like this, which actually does work*.</span><br />
<pre>
var /GLOBAL NSISRegPath
StrCpy $NSISRegPath "SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
var /GLOBAL EXERegPath
StrCpy $EXERegPath "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
${IF} ${AtLeastWinXP}
WriteRegStr HKLM "$NSISRegPath" "$INSTDIR\program.exe" "DisableNXShowUI"
${IF} ${RunningX64}
${DisableX64FSRedirection}
ExecWait '$SYSDIR\reg.exe add "$EXERegPath" /v "$INSTDIR\program.exe" /d "DisableNXShowUI"'
${EnableX64FSRedirection}
${ENDIF}
${ENDIF}
</pre>
<br />
<span style="line-height: 19px;">Finally! It works! </span><span style="line-height: 19px;">Total time of this endeavor is a little over an hour. Now I'm off for more compatibility testing. Windows 8 and Windows 2012 up next!</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-30136211841141968002011-12-20T19:39:00.003-06:002011-12-29T16:00:04.616-06:00What's your backup solution?Over the past twelve years I can remember three separate hard drive failures; two on work computers. Those are the ones I can remember, anyway. After the second one, I started getting serious about backups.<br />
<br />
I had written a VBScript back in 2000 that I used to archive my library every day using 7-zip - a poor man's version of source control. At first, I burned those archives to cd-rom every month or so. In fact, I still have a few of those cd-roms floating around my home office. Now, this didn't just include my archive; it included all the software I had dealt with - specifically the software used for integrations. It was mostly RADIUS servers, email servers and a couple ftp servers - along with license keys, notes, sql, help files, contact names and phone numbers (basically everything needed to start over in case of catastrophic loss).<br />
<br />
Eventually, I moved from writing software integrations to a proper software developer. I was actually doing double duty then, writing both software integrations and adding new features for the Platypus client. So, I got to enjoy the wonderous world of source control for Platypus, but integrations still stayed in zip's.<br />
<br />
Of course, after my second hard drive crash, that backup solution just wasn't enough. Cd-rom's take up physical space and required keeping track of where they all were. They did contain sensitive information, after all. So, I had to be careful with what I did with them. Anyway, what I really wanted was a daily reusable system that I could use to back up everything - including source code not ready for check-in - that preferably didn't involve cd-rw's. So, I bought my first USB drive - the <a href="http://www.overstock.com/Electronics/Soyo-Cigar-Pro-128MB-USB-Flash-Memory-Drive/190890/product.html">Soyo Cigar Pro 128MB USB Flash Memory Drive</a> for $72.94 on <span class="gI">Feb 7, 2003</span>. I know it isn't much now, but back then it was an amazing thing - solid state engineering at its best. <br />
<br />
At that point, I reconfigured my VBScript to zip and copy everything over to the flash drive, which I dutifully ran every day before going home. I even used a combination where I would fill up the flash drive, and then copy everything to a cd-rom. Actually, I only kept Friday backups in an effort to cut back on space, which meant I only had to burn a cd-rom every three to six months. That was much more acceptable than a new cd-rom every month, and it made sure I had valid daily backups with a decent historical archive.<br />
<br />
From there, I moved from using a desktop to a laptop for development and integrations fell by the wayside, but I still performed a daily backup of all the source code I was writing on a daily basis. I moved to a 256MB flash drive, then to a 512MB and finally to a 2GB. Since I didn't need integrations backed up, I dropped cd-rom's altogether and kept only source code backups for a month or two. If I needed something older, it belonged in source control.<br />
<br />
Today, all of that has changed. I'm back to using a desktop and I don't use either flash drives or cd-roms for backups. I now use a combination of RAID 1 and <a href="http://www.idrive.com/">IDrive</a> and <a href="http://www.vmware.com/">VMWare</a> for backups. Sure, it's only RAID 1 and it is <a href="http://en.wikipedia.org/wiki/Intel_Rapid_Storage_Technology">Matrix RAID</a>, at that (instead of a hardware based RAID); but that was enough when one of the drives died suddenly. Probably the best decision I made when getting my desktop from Dell was to get RAID pre-installed. Since then, there haven't been any problems, but it is nice to know I am covered in case of catastrophe. Even better, is the fact that I no longer have to put forth any effort to ensure my data is backed up.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-33994471079927240582011-08-03T01:29:00.002-05:002011-08-12T20:22:26.974-05:00Goodbye Firefox. It was nice knowing you.I've finally given up on Firefox. It was a great browser for its time, but it has become unusable for me. Don't get me wrong, I would still love to use it, but it has become too cumbersome.<br />
<br />
First a little background. This all takes place on my laptop, which has a mobile version of the <a href="http://en.wikipedia.org/wiki/List_of_Intel_Core_i7_microprocessors#.22Clarksfield.22_.2845_nm.29">i7 processor</a> and 4GB of RAM; neither of which should be scoffed at. Plus, I am running the <a href="http://www.mozilla.com/en-US/firefox/5.0/releasenotes/">latest and greatest version</a> of Firefox. Even with all that powerhouse, Firefox has been *pull my hair out* frustrating lately.<br />
<br />
This problem has been going on for a weeks now, but today was my final breaking point. Firefox has been running for a few/many days. I'm not exactly sure how long - probably over a week. Regardless, I had over 30 tabs open. Every now and then - especially when closing or switching tabs - the browser would hang for around a minute. Really!? Closing a tab takes a minute? That can't be right. I have a freakin' i7 processor and oodles of RAM.<br />
<br />
I checked <a href="http://msdn.microsoft.com/en-us/library/aa383614(v=vs.85).aspx">Task Scheduler</a> and <a href="http://technet.microsoft.com/en-us/sysinternals/bb896653">Process Explorer</a>. Nothing was taking up any significant amount of processor. Even Firefox was in single digits - as it should be with an i7 processor. Ok. Well, first thing, plugins. I disabled all but what I would consider essential plugins (I actually did this last week, but I wanted to see how it went before I made a rash judgement). The ones I kept are Adobe Acrobat, DivX, Quicktime, Flash, Silverlight and Adblock Plus. All well known and fairly stable plugins. Nothing wacky.<br />
<br />
Disabling plugins had no effect. At least nothing I could notice. Ok. Maybe it's <i>still </i>one of the plugins. Checked Task Scheduler and Process Explorer and killed all the <a href="http://support.mozilla.com/en-US/questions/704242">plugin-container.exe</a> processes I could find. Still no effect. In some of these cases, there weren't even any plugin-container.exe processes running. This leaves one major thing that I can think of. Mozilla needs to learn an age old lesson for large applications. <b><a href="http://en.wikipedia.org/wiki/DLL_Hell#Shared_in-memory_modules">Shared memory</a> is bad</b> - meaning you absolutely have to have some sort of separation or <a href="http://en.wikipedia.org/wiki/Process_isolation">isolation</a> between components (Now this doesn't go for every application, but browsers definitely fit this bill). Linux learned the lesson ages and ages ago by saying "<a href="http://en.wikipedia.org/wiki/Worse_is_better">don't create monolithic applications</a>". <a href="http://en.wikipedia.org/wiki/Protected_mode">Intel</a>, <a href="http://blogs.msdn.com/b/oldnewthing/archive/2011/01/19/10117410.aspx">Microsoft</a>, and <a href="http://www.google.com/chrome/">Google</a> learned this lesson. When will Mozilla? Well, as I just found out, <a href="https://wiki.mozilla.org/Electrolysis">they are</a>; but it's a long way from being done. (Plus, I'm already half way through with my rant. Why stop now?)<br />
<br />
Browsers really are the becoming the end-all-be-all of applications. While browsers don't actually do everything, they do provide a gateway for anything to be done. Kind of like what having a modem was back in the 80's. If you had one, you had access to the amazing world of wasting time. Even if it was just <a href="http://en.wikipedia.org/wiki/Aol">AOL</a> or <a href="http://en.wikipedia.org/wiki/CompuServe">Compuserve</a>, you were "connected". The same goes for browsers. If you have one - a relatively modern one - you can do your <a href="https://encrypted.google.com/search?q=banking+online">banking</a>, your <a href="http://www.amazon.com/">shopping</a>, talk <a href="https://encrypted.google.com/search?q=video+chat">face to face</a>; you can even watch freakin' <a href="http://www.netflix.com/">movies</a>. You can do all that and more - even at the same time. There's even a "programming" <a href="http://en.wikipedia.org/wiki/JavaScript">language</a> built in.<br />
<br />
Because they can dynamically do so much all at once, there is so much less room for error. If something goes wrong in one place, it shouldn't drag the system down with it. There's no reason for that. Firefox has released it's first set of features - <a href="https://wiki.mozilla.org/Firefox/Projects/OOPP">OOPP</a> (Out of Process Plugin) - that begins to deal with the problem. This prevents 3rd party code from causing Firefox to crash, but that isn't far enough. Each tab should be its <a href="http://blog.chromium.org/2008/09/multi-process-architecture.html">own process</a>. This is my number one favorite feature of Chrome. Opening and closing tabs is nigh instantaneous. (Yes, I realize Chrome hides the window/tab and does the real shutdown behind the scenes, but it's a separate process and doesn't slow down the rest of the "application".)<br />
<br />
Now, there is a down side to this. A separate process potentially means longer start-up times, more processor time, more RAM and sharing data across tabs/processes has got to be a nightmare. As a user, I don't really care about it. I just want the application to respond reasonably well, and Chrome's GUI does this better than any other browser out there. There's even a <a href="http://getfirebug.com/releases/lite/chrome/">Firebug</a> plugin for Chrome. So, I may even give up on Firefox for dev purposes, excepting some QA test cases.<br />
<br />
Now, as I found out about three-quarters of the way through my rant, Mozilla has the <a href="https://wiki.mozilla.org/Electrolysis">Electrolysis</a> (or e10s) project under way; but it's a long way from being done. When they finish, I'll reconsider switching back to Firefox; but until then, it's Chrome all the way.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-12624918129900933982011-07-18T02:04:00.009-05:002011-07-22T15:32:13.382-05:00Dynamic Linked Libraries (DLL) vs Static LibrariesWe no longer use DLL's with the Platypus Billing System, except where absolutely necessary. In some cases, with high level languages (such as Visual Basic 6 and Visual FoxPro) and 3rd party libraries (such as OpenSSL) written in C/C++, we have no other choice. Plus there are ActiveX/COM libraries (such as <a href="http://msdn.microsoft.com/en-us/library/ms763742%28v=vs.85%29.aspx">MSXML</a>, <a href="http://www.afterlogic.com/">Mailbee</a>, <a href="http://www.dbi-tech.com/">DBI</a>, and <a href="http://crystalreports.com/">Crystal Reports</a>), which cannot be linked to statically. But, in many cases, it can be avoided. <br />
<br />
Without getting into an argument over which is better or worse, when the stability of a product is on the line, having DLL's creates another <a href="http://en.wikipedia.org/wiki/Single_point_of_failure">point of failure</a>. For that reason alone, it was more important for us to statically link our C/C++ code where possible. Sure, the binaries may be larger and updates basically meant a re-install; but it has been well worth these minor difficulties. <br />
<br />
Since the switch to Visual C++ 2005 <i>and</i> static linking back in 2009, the number of C++ dependency issues we have encountered are still in the single digits - and that is only because of ActiveX/COM. Just to relay the point, here a few of the specific cases I have encountered over the past few years.<br />
<br />
<b>Case #1: <a href="http://php.net/">PHP</a> vs <a href="http://www.pidgin.im/">Pidgin</a></b><br />
<br />
Both PHP and Pidgin include a spell check library - <a href="http://aspell.net/">Aspell</a> - in the form of aspell-15.dll. Since the web pages for our product are written in PHP, I - of course - need PHP installed on my dev machine. Also, I have Pidgin installed for chatting with technical support - or anyone else at work when a face-to-face confab is not required.<br />
<br />
Now, normally these two products are not in conflict and everything works swimmingly. But, one day, I decided to grab one of the newer - more stable, secure, and compiled in VC 2008 - PHP editions from the <a href="http://windows.php.net/">PHP for Windows</a>. Everything worked fine at first. Then, as happens, I needed to reboot. Afterwards, Pidgin crashed every time I tried to start it up.<br />
<br />
After yanking my hair out using <a href="http://www.dependencywalker.com/">Dependency Walker</a> and <a href="http://technet.microsoft.com/en-us/sysinternals/bb896645">Process Monitor</a>, I finally figured out that it was because of Aspell. I renamed aspell-15.dll in the PHP folder and everything started working again. Because PHP was in the <a href="http://en.wikipedia.org/wiki/PATH_%28variable%29">system path</a>, Pidgin was loading the PHP version of the dll instead of the one in the Pidgin folder. <a href="http://msdn.microsoft.com/en-us/library/ms682586%28v=vs.85%29.aspx">It shouldn't have done this</a>, and I could find no logical reasoning for it, but that is what was happening.<br />
<br />
Regardless, I didn't have the time to look into it further. I knew the cause and could bypass it. Spell check is nice, but completely unnecessary for IM. So, I uninstalled Pidgin, and reinstalled it without the spell check feature. Problem solved - or, at least, dealt with.<br />
<br />
<b>Case #2: PHP vs <a href="http://www.openssl.org/">OpenSSL</a></b><br />
<br />
With our product, we include a COM DLL (tu_app.dll) for interacting with the <a href="http://www.opensrs.com/site/resources/documentation/api#email">Tucows Email Service</a>. This COM library was written in Visual C++ 6.0 and was linked to some severely old versions of the OpenSSL libraries. Again, because I decided to go mucking about with my installation of PHP, I broke yet another thing on my dev machine.<br />
<br />
I was performing some fixes for our integration with Tucows Email and had to do some unit tests. Every time I tried to load the COM object, the program would crash spectacularly. After some more hair pulling, I traced it down to the OpenSSL libraries. I replaced the DLL's installed by PHP with the one included in our installation set and it started working again.<br />
<br />
Problem solved? No, definitely not. While crashng my IM client is one thing, the possibility that someone could install a special version of PHP on the same machine as our product - which is normally the case - is another. Only the older versions of the OpenSSL libraries would work with our COM library.<br />
<br />
Those OpenSSL libraries were ancient and would not pass any scrutiny when it came to <a href="https://www.pcisecuritystandards.org/security_standards/documents.php?association=PA-DSS">PA-DSS</a>. Plus, having our product crash because we required using outdated and insecure versions of the OpenSSL libraries was completely unacceptable. So, we ported the code from Visual C++ 6.0 to Visual C++ 2005 and statically linked to OpenSSL. Now, the problem was solved.<br />
<br />
<b>Case #3: <a href="http://www.microsoft.com/technet/security/Bulletin/MS09-035.mspx">ATL Vulnerability</a></b><br />
<br />
When this problem first came out, I was working on a separate major rewrite/port of our C++ code - specifically a <a href="http://en.wikipedia.org/wiki/Windows_service">Windows service</a> for hosting our API - from Visual C++ 6.0 to Visual C++ 2005. I had everything working. It was beautiful and simple code, it compiled without warnings, it had no memory leaks, and it passed every test I threw at it.<br />
<br />
Next, came compatibility testing. After making an installation set for our product, I started testing on all the operating systems we supported - Windows 2000 up to Windows Vista/2008. Upon start up on Windows Vista and 2008, the service immediately crashed. It worked fine on Windows 2000 and XP.<br />
<br />
I checked the Eventlog and found a side-by-side dependency error. Considering this was my first venture into something newer than VC6, I wasn't fully competent with <a href="http://msdn.microsoft.com/en-us/library/aa374191%28v=vs.85%29.aspx">Application Manifests</a> at the time. So, I had no idea what this error really meant.<br />
<br />
I checked the installation set to make sure it included the Visual C++ runtime - and it did. I checked the installation log (and Add/Remove Programs) to make sure it installed - and it did. After even more hair pulling, I found out about the ATL update.<br />
<br />
The worst part was, no installation set for the Visual C++ runtime existed - which included the ATL fix. There is <a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=25287">now</a>, but there wasn't at the time (<a href="http://klonkers.blogspot.com/2011/07/application-manifests-visual-basic-6.html">or I just suck at using a search engine</a>). So, I could try to install the runtime files manually, but that involved a huge amount of effort and testing on all those OS's. Especially, for something that had to be done that night. I needed to finish my testing so we could release the next day (and possibly grab some sleep that night). Plus, I had no idea what DLL's to install or where to install them or how to deal with <a href="http://blogs.technet.com/b/askcore/archive/2008/09/17/what-is-the-winsxs-directory-in-windows-2008-and-windows-vista-and-why-is-it-so-large.aspx">WinSxS</a> from a <a href="http://nsis.sourceforge.net/Main_Page">NSIS</a> installation set.<br />
<br />
So, my only option was to switch to static linking. No more dependencies. No unnecessary points of failure. Or more simply, no more <a href="http://en.wikipedia.org/wiki/DLL_hell">DLL Hell</a>. Finally, problem solved and a few hours sleep before the release.<br />
<br />
<b>Case #4: <a href="http://www.microsoft.com/technet/security/advisory/2269637.mspx">DLL Preloading Vulnerability</a></b><br />
<br />
This is a generic definition of case #1. A DLL from an unexpected location is loaded instead of the intended one. While, case #1 wasn't officially an attack, it did crash a program and caused me a couple hours of unneeded stress.<br />
<br />
Now, in cases like this, there are officially two ways to deal with it. First, you can mitigate the attack surface by using <a href="http://msdn.microsoft.com/en-us/library/ms686203%28v=vs.85%29.aspx">SetDLLDirectory</a>. This limits the possibility of an attack, but doesn't eliminate it as I found out. The second way is to do away with the problem altogether by static linking. I am a firm believer that elimination is far better than mitigation - especially considering it requires no actual code change and reduces the amount of installation set testing required.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-2851658626696451142011-07-17T01:57:00.000-05:002012-04-30T22:20:31.473-05:00Application Manifests & Visual Basic 6Embedding <a href="http://msdn.microsoft.com/en-us/library/aa374191%28v=vs.85%29.aspx">Application Manifests</a> in Visual Basic 6 binaries is really easy. Microsoft even wrote a command line utility just for this purpose. Well, not for VB6 but for binaries in general. The <a href="http://msdn.microsoft.com/en-us/library/aa375649%28v=vs.85%29.aspx">Manifest Tool (mt.exe)</a>, which is included in both Visual Studio and the Windows SDK is extremely simple to use. The best part is that it handles any necessary padding and can update just about any binary with no fuss. <br />
<br />
Here's an example command line using the naming convention of Visual Studio 2005, where the manifest filename contains the program name with ".intermediate.manifest" appended.<b><code> </code></b><br />
<br />
<b><code>mt.exe -nologo -manifest "program.exe.intermediate.manifest" -outputresource:"program.exe;#1</code></b><br />
<br />
<b>And now for a story...</b><br />
<br />
When we were first confronted with the need for manifests - specifically for triggering <a href="http://msdn.microsoft.com/en-us/library/bb756929.aspx">UAC</a> prompts in our configuration tools written in VB6 - I performed my due diligence. I researched the topic thoroughly, I took examples of the manifests provided by Microsoft, and I tested on each and every Windows OS we supported - Windows 2000 all the way up to Windows Vista/2008.<br />
<br />
The one thing I couldn't find was a simple way to embed the manifest in those executables, that could be easily automated. The articles I read covered GUI tools like <a href="http://www.wilsonc.demon.co.uk/d10resourceeditor.htm">XN Resource Editor</a> and <a href="http://www.angusj.com/resourcehacker/">Resource Hacker</a>, writing my own C/++ program using <a href="http://msdn.microsoft.com/en-us/library/ms648049%28v=vs.85%29.aspx">UpdateResource</a>, a long winding route using the <a href="http://msdn.microsoft.com/en-us/library/aa381042%28v=vs.85%29.aspx">Resource Compiler (rc.exe)</a> or finally just leaving the manifest as a separate file.<br />
<br />
Even though manifests had been around since Windows XP, there wasn't a single article I could find that even mentioned the Manifest Tool. Even in the Microsoft articles I have found, there is never any mention of VB6 and the Manifest Tool together. Of course, VB6 was considered legacy by the time Application Manifests came out; so, while frustrating, I can't really blame them. I <i>can </i>blame my search engine skills, but that's no fun.<br />
<br />
Anyway, all but the last option were complicated, convoluted, or required too much effort. We, of course, finally settled on that last option - using external manifests - out of necessity to get something out the door. It wasn't until we started migrating code from Visual C++ 6.0 over to Visual Studio 2005 that I noticed the mt.exe command line in the build log, which was over a year and half later. Now, along with <a href="http://en.wikipedia.org/wiki/Code_signing">code signing</a>, through <a href="http://msdn.microsoft.com/en-us/library/8s9b9yaz%28v=vs.80%29.aspx">signtool.exe</a> the Manifest Tool is included in much of our automated build process, and I am much happier for discovering it.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-71350517882974259432011-07-09T02:51:00.002-05:002011-07-10T02:06:57.790-05:00Taxes Are Hard (Texas Tax Edition) - Part 2Taxes are hard; and as Texas has <a href="http://klonkers.blogspot.com/2011/07/taxes-are-hard-texas-tax-edition-part-1.html">proved so far</a>, Texas taxes are extraordinarily difficult. Even after all the specifics laid out in <a href="http://klonkers.blogspot.com/2011/07/taxes-are-hard-texas-tax-edition-part-1.html">part 1</a> of this post, a great deal of information is left before I can even begin talking about what it actually means.<br />
<br />
<b>State Tax</b><br />
Regardless of whether something is sold by a company in Texas or is sold to a customer in Texas, the state tax of 6.25% always applies. This is perhaps the simplest feature of Texas taxes. If it weren't for the $25 internet access exemption or the 20% web development/information service exemption, Texas state taxes would be easy.<b> </b><br />
<br />
<b>Local Sales Tax</b><br />
Beyond the state tax, the next type of tax that must be calculated is the local sales tax. This tax is based on the location of the seller's place of business.<br />
<br />
<b>Local Use Tax</b><br />
Next, after both the state tax and the local sales tax are calculated comes the local use tax. This tax is based on the location of the customer or where the customer receives the goods and services.<br />
<br />
<b>Further Complications of Local Taxes</b><br />
Both the local sales and local use taxes are further broken down into four different locale types: city, county, special purpose districts and transit. So, combined, this creates nine - count them nine - different types of taxes that go into the calculation.<br />
<br />
Next, after all that breakdown, city tax rates are different for each city, county tax rates are different for each county and so on. All combined, the local tax rate - for both local sales and local use taxes - cannot exceed 2%. This limiting factor of 2% works on a priority basis, adding each subsequent type to the total until the 2% is reached. If adding one of the local tax rates exceeds the 2% limit, only the amount necessary to reach the 2% limit is used. The order of the local tax rates is as follows.<br />
<ol><li>local city sales tax</li>
<li>local county sales tax</li>
<li>local special purpose district sales tax</li>
<li>local transit sales tax</li>
<li>local city use tax</li>
<li>local county use tax</li>
<li>local special purpose district use tax</li>
<li>local transit use tax</li>
</ol>In addition, city taxes do not apply if outside of the city limits. So, a company located outside of the city limits, the local city sales tax will not apply; and if a customer is located outside of the city limits, the local city use tax will not apply.<br />
<br />
Also, while the terms "sales" and "use" imply a different set of rules or percentages, they actually don't. Local taxes rates are the same for both sales and use. Plus, when reporting local taxes, they are done based on the different locale types: city, county, special purpose district, and transit. Beyond the initial calculation, the terms sales and use are not applied (at least, to my knowledge).<br />
<br />
Finally, along those same lines, duplicates are ignored. Local sales taxes for the seller are calculated; then, local use taxes for the customer are calculated - ignoring any the local use tax for duplicates. For example, if both the company and the customer are located within the same county, the local county sales tax will apply but the local county use tax will not; or more apply put, the local city tax is only calculated once.<br />
<br />
The information provided in this article is just a summary of the Texas local tax calculations. The <a href="http://www.window.state.tx.us/taxes/">Window on State Government</a> web site provides an article - and is the basis for this post - which covers may different scenarios with specific examples for each in the <a href="http://www.window.state.tx.us/taxinfo/taxpubs/tx94_105.pdf">February 2009 Local Sales and Use Tax Bulletin - Guidelines for Collecting Local Sales and Use Tax</a>.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-45791644319623933042011-07-09T00:25:00.004-05:002011-07-10T02:06:57.791-05:00Taxes Are Hard (Texas Tax Edition) - Part 1Taxes are hard, and along the lines of "don't mess with Texas", internet taxes in Texas go above and beyond the norm. The basics of Texas internet taxes are as follows.<br />
<br />
<b>Note: </b>Because of the complications of Texas taxes, this article is broken down into several manageable posts. The first two, of which, specifically cover a summary of rules for Texas taxes.<br />
<br />
<b>Internet Access Service</b><br />
<ul><li>Internet access services (including enhancements such as static ip addresses, email and instant messaging) are taxable. <a href="http://law.onecle.com/texas/tax/151.0101.00.html">(Texas Tax Code - Section 151.0101(a)(16))</a></li>
<li>Up to $25 for internet access per month are tax exempt. <a href="http://law.onecle.com/texas/tax/151.325.00.html">(Texas Tax Code - Section 151.325)</a></li>
</ul><b>Web Development and Information Services</b> <br />
<ul><li>Web development and information services (including web page design and web hosting) are taxable. <a href="http://law.onecle.com/texas/tax/151.0101.00.html">(Texas Tax Code - Section 151.0101(a)(12))</a></li>
<li>Twenty percent (20%) of the value of data processing and information services are tax exempt. <a href="http://law.onecle.com/texas/tax/151.351.00.html">(Texas Tax Code - Section 151.351)</a></li>
</ul>Seems simple, doesn't it? Now for the semantics.<br />
<ul><li>Taxes for these services went into effect on October 1, 1999. <a href="http://aixtcp.cpa.state.tx.us/opendocs/open17/9906479l.html">(Document 9906479L)</a></li>
<li>Late fees are not taxable, but reinstatement (reactivation) fees are taxable <a href="http://aixtcp.cpa.state.tx.us/opendocs/open20/200001959l.html">(Document 200001959L)</a></li>
<li>The $25 exemption applies per purchaser not per account. So, if the purchaser has multiple accounts, up to $25 is exempt for all the accounts combined. <a href="http://law.onecle.com/texas/tax/151.325.00.html">(Texas Tax Code - Section 151.325(c))</a></li>
<li>A seller who uses catalogs or the Internet to sell goods is treated the same as any other seller of taxable items. If you purchase merchandise through a catalog or the Internet from a seller located in Texas, you owe Texas sales tax on the purchase. If you purchase merchandise through a catalog or the Internet from a seller located outside of Texas and use the taxable item in Texas, then you owe Texas use tax on the purchase. An out-of-state mail-order company or an Internet company may hold a Texas Sales and Use tax permit and collect Texas tax. If the out-of-state seller does not have a Texas permit or does not collect Texas use tax, the use tax is due and payable by the purchaser. <a href="http://www.window.state.tx.us/taxinfo/sales/faq_use.html#use3">(Texas Sales Tax FAQ)</a></li>
<li>Internet access taxes for Texas are grandfathered under <a href="http://en.wikipedia.org/wiki/Internet_Tax_Freedom_Act">Internet Tax Freedom Act</a> and are considered exempt from that act.</li>
<li>The state tax rate is 6.25%. <a href="http://www.window.state.tx.us/taxinfo/sales/">(Window on State Government - Texas Taxes - Sales and Use Tax)</a></li>
<li>The city tax rate cannot exceed 2%. <a href="http://www.window.state.tx.us/taxinfo/sales/">(Window on State Government - Texas Taxes - Sales and Use Tax)</a></li>
<li>The county tax rate cannot exceed 1.5%. <a href="http://www.window.state.tx.us/taxinfo/sales/">(Window on State Government - Texas Taxes - Sales and Use Tax)</a> </li>
<li>The combined tax rate cannot exceed 8.25%, where 6.25% is state taxes and the remaining 2% is comprised of local sales or use taxes in the form of city, county, transit and special district taxes. <a href="http://www.window.state.tx.us/taxinfo/sales/">(Window on State Government - Texas Taxes - Sales and Use Tax)</a></li>
</ul>Continued in <a href="http://klonkers.blogspot.com/2011/07/taxes-are-hard-texas-tax-edition-part-2.html">Part 2</a>. <br />
<ul></ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-17521665875089180952011-07-08T20:25:00.002-05:002012-04-30T22:20:31.469-05:00Application Manifests, UAC & Windows Vista - Part 2Way back in the days of Windows 2000, <a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=B996E1E7-A83A-4CAE-936B-2A9D94B11BC5&displayLang=en">new guidelines</a> were introduced to improve the overall usability and security of the OS. Although, in order to maintain compatibility, none of these guidelines were actually enforced at the time. Then, when Windows Vista was released, the game changed. Those guidelines were no longer optional, but there was a backup plan.<br />
<br />
<b>New Guidelines for Windows 2000</b><br />
<ol><li>Only binaries or read only files should be stored in Program Files.</li>
<li>Any documents or user created files should be stored in My Documents.</li>
<li>Temporary files should be created in the user (or system) Temp folder.</li>
<li>Anything else should be written to Application Data.</li>
</ol>Now, in a perfect world, everyone would have read those guidelines and started following them. After all, there is <a href="http://msdn.microsoft.com/en-us/library/bb762494%28v=vs.85%29.aspx">no</a> <a href="http://msdn.microsoft.com/en-us/library/bb762204%28v=vs.85%29.aspx">shortage</a> <a href="http://msdn.microsoft.com/en-us/library/bb762181%28v=vs.85%29.aspx">of </a><a href="http://technet.microsoft.com/en-us/library/bb742580.aspx">documentation</a> <a href="http://support.microsoft.com/kb/252652">on</a> <a href="http://support.microsoft.com/kb/310294">how</a> <a href="http://support.microsoft.com/kb/241733">to</a> <a href="http://support.microsoft.com/kb/227051">implement</a> <a href="http://support.microsoft.com/kb/187674">them</a>, but things rarely go according to plan. Even we were not immune to this thinking. I guess it could be summed up as "Well, if Microsoft doesn't care if we do it, then why should we change?" And, you can't exactly cry foul just because you didn't read the rules, <a href="http://en.wikipedia.org/wiki/Arthur_Dent">can you</a>?<br />
<br />
With the introduction of UAC, it was no longer possible to write to Program Files without administrative privileges, but somehow older programs still worked. This is where the the requestedExecutionLevel flag in Application Manifests comes into play. If the flag is missing from the manifest, the OS does its fancy <a href="http://msdn.microsoft.com/en-us/library/bb756960.aspx">footwork</a> of guessing whether the program should be elevated. If the program is not elevated, then the program is run in compatibility mode. Any attempts to write to a system folder - such as Program Files or System32 - or write to a system registry hive - such as HKLM - will result in virtualization.<br />
<br />
While you may think your program is writing to HKLM, it's not. Not really. It may look like it to you. Even to the program itself, it will appear that way, because it is actually reading from a virtualized section of the registry. This means that in your own little world, everything is working as you expected, but it is not directly affecting the OS. So, any changes you make to your little world don't affect anyone else who logs into the OS. This is one of the key points that makes UAC really work. Without this, Vista would truly be the nightmare that you hear in those Mac commercials.<br />
<br />
Still, even with virtualization in place, some wacky things can occur. for example, there's a specific case I found with the <a href="http://technet.microsoft.com/en-us/sysinternals/bb897443">SDelete</a> utility provided by SysInternals, which runs in compatibility/virtualization mode. If the program is run as unpriviledged and is passed a file located in Program Files, it simultaneously finds the file and cannot find the file. It actually finds the file in Program Files, and then attempts to open a file of the same name in the Virtual Store. So, after all that, it reports a success saying the file was correctly wiped and deleted, but the file in Program Files is never touched.<br />
<br />
<b>User Account Control (UAC)</b><br />
<ul><li><a href="http://msdn.microsoft.com/en-us/library/bb756945.aspx">UAC Architecture</a> </li>
<li><a href="http://msdn.microsoft.com/en-us/library/bb756973.aspx">Designing UAC Applications for Windows Vista</a> </li>
<li><a href="http://msdn.microsoft.com/en-us/library/bb756960.aspx">New UAC Technologies for Windows Vista</a> </li>
<li><a href="http://support.microsoft.com/kb/927387">Common file and registry virtualization issues in Windows Vista or in Windows 7</a> </li>
<li><a href="http://channel9.msdn.com/Shows/Going+Deep/UAC-What-How-Why">UAC - What. How. Why.</a> </li>
</ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-13350047.post-33943369048804202362011-07-08T18:35:00.015-05:002012-04-30T22:20:31.477-05:00Application Manifests, UAC & Windows Vista - Part 1Support for Manifest Resources continued with Windows Vista. In addition to the new Shell Common Controls library and Side-by-side assemblies introduced in Windows XP, support for <a href="http://msdn.microsoft.com/en-us/library/dd464660%28VS.85%29.aspx">High-DPI Applications</a> and <a href="http://technet.microsoft.com/en-us/library/cc709691%28v=ws.10%29.aspx">User Account Control (UAC)</a> was added to the Manifest Resource. The most scrutinized feature of the two, of course, is User Account Control, which provided additional security to the operating system by specifying within the program what type of permission was required for using the program.<br />
<br />
With Windows XP and lower, an administrator was always logged in as an administrator and a restricted user was always logged in as a restricted user. This meant that any program executed by an administrator would always be executed with full administrative rights. While any program executed by a restricted user would never have administrative privileges.<br />
<br />
With the introduction of UAC, if a program required administrative privileges, such as writing to HKLM in the registry or writing to a system folder, the OS would notify the user of the required privileges before executing potentially damaging code - even when logged in as an administrative user. The OS determined this through the <a href="http://msdn.microsoft.com/en-us/library/bb756929.aspx">requestedExecutionLevel</a> flag in the application manifest. If this flag was missing, the OS would do some fancy <a href="http://msdn.microsoft.com/en-us/library/bb756960.aspx">footwork</a> and make a guess.<br />
<br />
The key point here is that by embedding the required privilege within the program, a user - even a user with administrative privileges - did not have to work in a completely unprotected environment. This helps restrict access to much of the operating system when performing day-to-day tasks; and when malicious software is introduced on the machine, the restricted access given to that software should help mitigate any damage.<br />
<br />
<b>Vista Styles</b><br />
<ul><li><a href="http://www.microsoft.com/downloads/en/details.aspx?familyid=E49820CB-954D-45AE-9CB3-1B9E8EA7FE8C&displaylang=en">Microsoft Download - Windows Vista/7 User Interface Guidelines</a> </li>
<li><a href="http://msdn.microsoft.com/en-us/library/aa468595.aspx">MSDN Library - How to Create the Best User Experience for Your Application</a> </li>
</ul><b>User Account Control (UAC)</b><br />
<ul><li><a href="http://msdn.microsoft.com/en-us/library/aa905330.aspx">MSDN Library - The Windows Vista and Windows Server 2008 Developer Story: Windows Vista Application Development Requirements for User Account Control (UAC)</a> </li>
<li><a href="http://msdn.microsoft.com/en-us/library/bb530410.aspx">MSDN Library - Windows Vista Application Development Requirements for User Account Control Compatibility</a> </li>
<li><a href="http://msdn.microsoft.com/en-us/library/bb756929.aspx">MSDN Library - Designing UAC Applications for Windows Vista - Step 6: Create and Embed an Application Manifest (UAC)</a> </li>
<li> <a href="http://technet.microsoft.com/en-us/library/cc709691%28v=ws.10%29.aspx">Microsoft TechNet - User Account Control Step-by-Step Guide</a></li>
<li><a href="http://technet.microsoft.com/en-us/library/cc709628%28v=ws.10%29.aspx">Microsoft TechNet - Understanding and Configuring User Account Control in Windows Vista</a></li>
</ul><b>Compatibility</b><br />
<ul><li><a href="http://blogs.msdn.com/b/cjacks/archive/2006/08/21/711240.aspx">The App Compat Guy - Exploring Manifests Part 1: Side by Side Assemblies</a></li>
<li><a href="http://blogs.msdn.com/b/cjacks/archive/2006/09/08/exploring-manifests-part-2-default-namespaces-and-uac-manifests-in-windows-vista.aspx">The App Compat Guy - Exploring Manifests Part 2: Default Namespaces and UAC Manifests in Windows Vista</a></li>
<li><a href="http://blogs.msdn.com/b/cjacks/archive/2010/04/18/app-compat-bug-explained-the-mysterious-black-background-in-visual-basic-6-vb6-forms-and-controls.aspx">The App Compat Guy - App Compat Bug Explained: The Mysterious Black Background in Visual Basic 6 (VB6) Forms and Controls</a></li>
</ul>Unknownnoreply@blogger.com0