Running the Less.js command-line compiler on Windows

There have been some interesting developments recently in the field of CSS pre-processors. CSS pre-processors work around the very limited syntax of CSS by allowing you to create your stylesheets using a more powerful, expressive syntax which then gets turned into plain CSS for consumption by all the main browsers. A couple of ones that I’ve come across are SASS and LESS. LESS is the one I’ve felt most comfortable with because it’s simply an augmentation of the CSS which allows you to incrementally introduce its syntax into your stylesheets.

For example LESS supports variables:

@brand_color: #4D926F;
#header {
   color: @brand_color;
}
h2 {
   color: @brand_color;
}

nested rules:

#header {
  color: red;
  a {
    font-weight: bold;
  }
}

…mixins, operations on colors and size, etc. Check out the  lesscss.org homepage for more.

LESS was originally a Ruby gem, but now also has implementations on ASP.NET (dotlesscss.org) and PHP. LESS has now (inevitably) been re-implemented in JavaScript by Alexis Sellier (github.com/cloudhead/less.js). As well as supporting pre-processing *.less files into *.css via the command-line, it can also be actually run live, directly in your browser!

<link rel="stylesheet/less" href="stylesheets/main.less" type="text/css" />
<script src="script/less-1.0.38.min.js"></script>

I’m not sure I’m quite ready to take the plunge running it live, in-browser on sites just yet, although maybe I shouldn’t be according to Dmitry Fadeyev:

Wouldn’t live processing lag? Not really. Two reasons for this. One: Less.js has been written from the ground up for great performance, so even browsers with poor JavaScript implementation should still run it very well (Less.js is about 40 times faster than the Ruby implementation—so suffice to say it’s a lot faster.). Two: On modern browsers that support HTML5, Less.js will cache the generated CSS on local storage, making subsequent page loads as fast as pure CSS.

Running on Windows

The command-line compiler lessc is targeted to *nix-based platforms and requires node.js which, the last time I checked, doesn’t run on Windows (UPDATE: it runs fine under Cygwin, there’s a nice simple standalone version here). But Windows has had the ability to run JavaScript directly since the 1990’s using Windows Script Host. So I took the latest distribution copy of less.js from GitHub at https://github.com/cloudhead/less.js/tree/master/dist/ and included it via a *.wsf file and stubbed/faked/implemented a few things like window, document and XMLHttpRequest that less.js assumes will be present (which are presumably provided by node.js?), and added a bit of command-line argument handling.

Download

Browse the code and download from GitHubhttps://github.com/duncansmart/less.js-windows and feel free to fork it and send me pull requests!

Usage

To use it, invoke lessc.wsf via cscript.exe like so:

cscript //nologo lessc.wsf input.less [output.css] [-compress] 

I’ve also added a less.cmd shim which will simplify it to just:

lessc input.less [output.css] [-compress] 

If you don’t specify an output.css the result is written to standard output. The -compress option minifies the output. I’ll look into implementing the other command-line arguments supported by lessc in due course.

I’ve added a couple of test files, so you can see if it’s working like so:

C:codelessc-wsh>lessc test.less
/* Variables */
#header {
  color: #4d926f;
}
h2 {
  color: #4d926f;
}
/* Mixins */
#header {
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}
...

Future

I may look into hooking this into Visual Studio’s T4 support so that the *.css files are generated as soon as you save the *.less files in Visual Studio. (UPDATE: See Phil Haack’s T4CSS that does this, instead using  the .NET port of LESS. Thanks to David De Sloovere for pointing this out.)

Update

Mark Lagendijk has created a nice little Windows GUI for the script. Check it out at http://winless.org.

Follow @duncansmart on Twitter

SOLVED: “The type initializer for ‘System.Drawing.ToolboxBitmapAttribute’ threw an exception”

This exception has been plaguing our automated error reports inbox for a while:

System.TypeInitializationException: The type initializer for 'System.Drawing.ToolboxBitmapAttribute' threw an exception. 
  ---> System.Runtime.InteropServices.ExternalException: GDI+ is not properly initialized (internal GDI+ error).
  at System.Drawing.Bitmap..ctor(Stream stream)
  at System.Drawing.ToolboxBitmapAttribute..cctor()
  --- End of inner exception stack trace ---
  at System.Reflection.CustomAttribute._CreateCaObject(Void* pModule, Void* pCtor, Byte** ppBlob, Byte* pEndBlob, Int32* pcNamedArgs)
  at System.Reflection.CustomAttribute.CreateCaObject(Module module, RuntimeMethodHandle ctor, IntPtr& blob, IntPtr blobEnd, Int32& namedArgs)
  at System.Reflection.CustomAttribute.GetCustomAttributes(Module decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes)
  at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeType type, RuntimeType caType, Boolean inherit)
  at System.RuntimeType.GetCustomAttributes(Type attributeType, Boolean inherit)
  at System.ComponentModel.ReflectTypeDescriptionProvider.ReflectGetAttributes(Type type)
  at System.ComponentModel.ReflectTypeDescriptionProvider.ReflectedTypeData.GetAttributes()
  at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.DefaultTypeDescriptor.System.ComponentModel.ICustomTypeDescriptor.GetAttributes()
  at System.ComponentModel.TypeDescriptor.GetAttributes(Type componentType)
  at System.Web.UI.ViewStateModeByIdAttribute.IsEnabled(Type type)
  at System.Web.UI.Control.SaveViewStateRecursive()
  at System.Web.UI.Control.SaveViewStateRecursive()
  at System.Web.UI.Control.SaveViewStateRecursive()
  at System.Web.UI.Control.SaveViewStateRecursive()
  at System.Web.UI.Control.SaveViewStateRecursive()
  at System.Web.UI.Page.SaveAllState()
  at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

The page it occurs on is the login page of an ASP.NET WebForms app which happens to be the default.aspx page in the root of the site: a page that gets a lot of hits. It happened sporadically and was impossible to reproduce: likely some odd timing issue. But when it did happen, it brought the whole web app down.

There appears to be an official hotfix for System.Drawing.dll at http://support.microsoft.com/kb/975410. You will need to contact Microsoft Support for this though. Rather than use up one of our Microsoft Partner support hits, a quick, simple solution dawned on me.

Our solution

Looking at the stack trace, it’s clear that the issue occurs when the page’s ViewState is being serialised. Therefore, the solution (OK, more of a workaround) in our case was simply to disable ViewState on the page:

<@Page … EnableViewState="false" %>

Now this might not work for you because your page, or controls on your page may rely on ViewState. For example, if you have OnChange event handlers on textboxes: these rely on having the “before” stashed in ViewState. But we rarely use ViewState anywhere in the application, so it was especially galling that we’d left it enabled on one of the the busiest pages in the app.

ASP.NET Padding Oracle Detector

UPDATE: Patch available, forget the workarounds, install it now: http://weblogs.asp.net/scottgu/archive/2010/09/28/asp-net-security-update-now-available.aspx

If you develop or run an ASP.NET based site you need to be aware of a potential attack that has been reported widely, known as the padding oracle exploit whereby encrypted values can be systematically decrypted or encrypted ultimately allowing an attacker to log into a forms authenticated site as a user of their choosing or download arbitrary files. Troy Hunt has an excellent write-up of the crypto stuff at the core of the attack.

There are some immediate things you can do that ScottGu outlines which involve updating <customErrors> in your web.config. But I felt that there are plenty of ASP.NET sites out that have their own way of dealing with errors which may be vulnerable due to the way they report errors.

One example is Exchange Outlook Web Access (Exchange 2007 at least), which by default exposes the underlying error details (helpfully including a stacktrace no less!) in its default error page and therefore can be potentially used as a padding oracle.

E.g. https://exchange.example.com/owa/auth/webresource.axd?d=foo:

image

This error page is served up as a 200 OK so it can’t be mitigated by a load balancer easily.

Whether an attack can actually be escalated against OWA from this is unknown to me at this time, nor which versions would be affected. OWA might not be using standard Forms Auth etc, but I haven’t heard the definitive word on this. Some kind soul has published steps on how to mitigate this apparent OWA vulnerability on the ASP.NET forums.

Anyway, I looked the attack against ASP.NET general and came up with what I thought was some useful information and posted this on the ASP.NET forums:

I’ve done some digging and come up with what I think is useful information for you if you have a custom error handling solution in place instead of or as well as the usual ASP.NET <customErrors> stuff.

From comments on ScottGu’s post it seem to be that the main suspect to be the actual padding oracle is WebResource.axd (possibly other axd’s).

  • If you look in .NET Reflector at the IHttpHandler.ProcessRequest method in  System.Web.Handlers.AssemblyResourceLoader there’s a call to Page.DecryptString early on.
  • This is the thing that will cause a HTTP 500 status to be returned if it fails, e.g. if the padding, etc in Request.QueryString[“d”] is invalid
  • If the attacker manages to get the padding right, then it continues on, ultimately to call throw new HttpException(404…)
    It’s this differentiation: is the padding correct (404) or not (500) that is at the root of the exploit: the padding oracle.

If your error handling returns exactly the same response for both – it masks the oracle. To test if you’re vulnerable externally, a simple test is to request both:

  • webresource.axd?d=foo
  • webresource.axd with no parameters

and check using FiddlerTool, or FireBug that the entire response is identical for both including the status and all the headers (except for the Date header I guess!).

Of course I may have missed something, but I hope this information helps you until the official fix comes out.

Using the script

To automate the above simple test I’ve written a little Windows Script Host script in JavaScript that can be used in a couple of ways:

  • double-click it and you will be prompted for a site URL
  • or invoke from a Command Prompt passing the site URL as the first argument. e.g.:
    cscript AspNetPaddingOracleDetector.js http://mysite.example.com

Here’s what it looks like if you point it at a site that may be vulnerable:

C:>cscript //nologo AspNetPaddingOracleDetector.js http://mysite1.example.com
Testing site: http://mysite1.example.com/
MIGHT BE VULNERABLE: HTTP status mismatch

=== Response 1 ===
404 Not Found

=== Response 2 ===
500 Internal Server Error

And here’s what it look like if the site does not appear to be exposing an obvious padding oracle:

C:>cscript //nologo AspNetPaddingOracleDetector.js http://mysite2.example.com/blah
Testing site: https://mysite2.example.com/blah/
Site might be OK: WebResource.axd is not acting as a padding oracle

Please use your judgement in interpreting the output and do not assume that you are safe/vulnerable based solely on its output.

To test Exchange Outlook Web Access typically you will want to run the script against the /owa/auth virtual directory, e.g. https://msexchange.example.com/owa/auth.

What about ScottGu’s script?

The difference between this script and the one mentioned by ScottGu is that this one actually does a simple test of your site from the outside to see if the mitigations you have put in place are likely to have helped you. For example you may have put an iRule on your F5 BigIP to mitigate the issue: this will help you test if that has been effective.

Plz send me teh codez

Download the script (right-click, save as) and just double-click it to try it out. Or view the script source on Google Code.

Hope that helps!

Follow @duncansmart on Twitter

Solving SMTP “554 Permanent scan failure” non-delivery errors

Recently some users started getting non-delivery reports (NDRs) from our Exchange server with messages like the following:

554 Permanent scan failure. Email Session ID: {4C209A7E-0-3A6A8C0-1FFFF}

Looking at the SMTP logs (C:Program FilesMicrosoftExchange ServerTransportRolesLogsProtocolLogSmtpSend) showed the offending sessions looking something like this:

* attempting to connect
+
< 220 mail.example.com ESMTP
> EHLO smtp.example.com
< 250-mail.example.com
< 250-8BITMIME
< 250-SIZE 10485760
< 250 STARTTLS
* 1600 sending message
> MAIL FROM:<Jo.User@example.com> SIZE=1061757
< 250 sender <Jo.User@example.com> ok
> RCPT TO:<A.N.Other@example.com>
< 250 recipient <A.N.Other@example.com> ok
> DATA
< 354 go ahead
< 554 Permanent scan failure. Email Session ID: {4C209928-2-3A6A8C0-1FFFF}
> QUIT
- Remote

Very odd as I couldn’t find any information about this “Permanent scan failure”.

Then looking at the SMTP message headers of messages that did get through (Outlook hides them away in the message properties as “Internet headers”) on the receiving side offered up a clue:

Received: from mail.example.com (4.3.2.1) by blah.example.com
(5.6.7.8) with Microsoft SMTP Server (TLS) id 8.1.340.0; Thu, 18 Mar
2010 10:17:49 -0400
Received: from smtp.example.com (HELO smtp.example.com) ([1.2.3.4]) by
mail.example.com with SMTP; 18 Mar 2010 10:19:34 -0400
X-CheckPoint: {4BA23672-7-3A6A8C0-7B6}
Message-ID: <CAC3AC395FD04CB1BB7DCEC764E7816E@example.com>
From: fred <fred@example.com>
To: <johndoe@example.com>
...

The CheckPoint firewall was injecting an ID into the headers which had exactly the same format as the “Session ID” from the ones that were failing with “Permanent scan failure”.

So unbeknownst to us CheckPoint was proxying/filtering the SMTP traffic and barfing on it for some reason.  When we switched off the SMTP checks that CheckPoint was doing (they weren’t required as we have another mail gateways in place) the problem went away.

Macro to Restart Visual Studio Elevated

Kevin Dente ponders on Twitter:

Wonder if it would be possible to create a Visual Studio add-in or macro that re-launches VS elevated, with the current project, then exits

This is something I’ve been meaning to do for a while, as often I’ll open a Web Application in Visual Studio configured to run under IIS and be met with the following:

The Web Application Project is configured to use IIS. To access local IIS Web sites, you must run Visual Studio in the context of an administrator account..

Running anything elevated is easy, you just need to call ShellExecute (the .NET equivalent is System.Diagnostics.Process.Start) with the “RunAs” verb, so it’s simply a matter of starting Visual Studio’s devenv.exe passing the path to the current solution.

So here goes: copy and paste this into a Macro Module (ALT+F11) then wire up to a toolbar button as appropriate:

Sub ElevateVisualStudio()

    Dim slnPath As String = DTE.Solution.FullName
    DTE.Solution.Close(True)

    Dim startInfo As New System.Diagnostics.ProcessStartInfo(DTE.FullName, slnPath)
    startInfo.Verb = "RUNAS"
    System.Diagnostics.Process.Start(startInfo)

    DTE.Quit()

End Sub

Works On My Machine™, etc and only tested on Visual Studio 2008.

Using Windows 7’s “XP Mode” to run IE 6, IE 7 and IE8 side-by-side

Windows 7’s XP Mode is essentially a Windows XP virtual machine that runs in the new Windows 7 version of Virtual PC. This new edition of Virtual PC includes cool features such as seamless windows. The main reason I’m interested in this is to run older versions of Internet Explorer for testing purposes. IE8’s compatibility mode does a pretty good job of emulating IE7 but there are differences, so I investigated how to get “real” IE7 running under Windows 7’s XP Mode, without losing IE6.

Out of the box, the Virtual PC image is Windows XP SP3 with IE6. The trick to getting IE6 to appear as a seamless window like this is to launch the Virtual Windows XP virtual machine and in the VM, create a shortcut in the “All Users” Start Menu or desktop:

image

After a short delay, the shortcut will be duplicated into the Windows 7 host’s start menu:

image

When you launch this shortcut in Windows 7, the main Virtual PC window will close and the application will be launched and projected onto your desktop.

Creating a VM for IE7

You can’t install IE7 side-by-side with IE6 on the same machine, so to run IE7 at the same time as IE6 we will need to create a new VM. Unfortunately, if you run the VirtualWindowsXP.msi setup again you’ll get a message saying “Setup has detected that Virtual Windows XP is already installed”:

image

The workaround is to create a new instance of the VM manually using the supplied VHD as the base disk image. To do this do the following:

Open the Virtual Machines folder from the Start Menu and click Create virtual machine:

image

Specify a name and location for the virtual machine:

image

For memory I specified 256MB, which should me more than enough for just running IE7:

image

Here’s the important bit. Choose “Create a virtual hard disk using advanced options”

image

…and then choose a Differencing disk. This is the same way that the default Virtual Windows XP VM is set up:

image

If you want, you can change the default name and location (I didn’t bother):

For the parent virtual hard disk choose the original Virtual Windows XP virtual disk, which on my machine was at C:Program FilesVirtual Windows XPVirtual Windows XP.vhd:

image

Now start the new Virtual PC you just created from the Virtual Machines folder and complete Windows Setup as appropriate, choosing a computer name unique for your network and an Administrator password:

image

When that’s done:

  • Enable Integration Features from the Tools menu of the Virtual PC window
    • For credentials enter Administrator and the password you entered during setup.
    • I chose to Remember my credentials for convenience
  • download and install IE7 in the VM,

When IE7 has installed and rebooted, create a shortcut to IE7 in the “All Users” start menu which, after a short delay, will create a corresponding shortcut in the Windows 7 start menu of the host.

image

So here’s the end result, IE6, IE7 and IE8 all running on Windows 7:

image

Ahhh, 3 generations, all together – don’t they look adorable?

Fixing WebSVN “Unable to call svn command” error

WebSVN is a great PHP web-based interface to Subversion that we run on our IIS build server. But, after updating to a more recent build we started getting errors like the following when viewing diffs:

Unable to call svn command "svn --non-interactive --config-dir /tmp"

The source of the error is in the getFileContents function in svnlook.php, where it’s piping the output of svn cat to GNU Enscript (for syntax highlighting) and then parsing the output of that using sed. I guessed that maybe the regex that sed is using isn’t being escaped properly for the Windows command line and therefore failing.

But I noticed that all of this code was in an if($config->useEnscript) block. Just before that is an if($config->useGeshi) block that looks a lot simpler. Simpler because GeSHi is PHP-based syntax highlighter, rather than an external command whose output requires special parsing. So I went to our include/config.php and added the $config->useGeshi(); call (as detailed in the distconfig.php template config file), and it all started working happily again!

Unzipping/extracting MSI files

If, like me, you are constantly wanting to just extract the files from a Windows Installer MSI file quickly, then this is for you.

My ZIP utility of choice 7-Zip appears to support extracting MSI files but in fact extracts all the various weird and wonderful binary streams in the MSI rather than simply just the actual files. Thankfully I stumbled across a Windows Installer switch today after typing msiexec /? that does the job perfectly: the /a “administrative install” switch, e.g.:

msiexec /a foo.msi /qb TARGETDIR="C:TEMPFoo"

So, what I’ve done is packaged this up as a little registry tweak that conveniently lets you do this by simply right clicking a file like so:

image

Copy and paste the following into a *.reg file and double-click it:

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USERSoftwareClassesMsi.PackageshellExtract MSIcommand]
@="msiexec.exe /a "%1" /qb TARGETDIR="%1 Extracted""

Hope that helps!

Fixing “Provider: Unspecified error” when querying LDAP with the ADsDSOObject OLEDB Provider

As part of our logon script we have a Windows Script Host script that was failing with “Provider: Unspecified error” (mmn, helpful) but only on some Windows XP machines.

The offending line of code looked like this:

rs = con.Execute("<LDAP://DC=example,DC=com>; (sAMAccountName="+ username +"); ADsPath; subTree")

After some trial and error the fix was this (see if you can spot the difference):

rs = con.Execute("<LDAP://DC=example,DC=com>;(sAMAccountName="+ username +");ADsPath;subTree")

Can you see what it is? No spaces after the semicolons!

Alternatively the SQL-like syntax also seems to be a bit more forgiving:

rs = con.Execute("SELECT ADsPath FROM 'LDAP://DC=example,DC=com' WHERE sAMAccountName='"+ username +"'")

It appears that with some later version of ADSI ADsDSOObject (or to give it its full title, the “OLE DB Provider for Microsoft Directory Services”) the query syntax strictness has been relaxed. In any case “Unspecifed error” appears to mean “Syntax error” in this case.