My own creepypasta moment

I came across this comic on My Korean Husband and the third panel reminded me of my very own creepypasta moment…

I few years ago I was having trouble sleeping during a warm night in Perth. It was about 2am, and still about 30°C (86°F). We had the window open but there wasn't a breath of air. Meanwhile, my wife was sleeping peacefully next to me.

But she started to stir a little bit, mumbling in her sleep as she sometimes does. She then said a word in Korean, and though I didn't know what it meant at the time, it was simple enough for me to remember: 괴물, pronounced like "gwemul". I didn't think anything of it, but it was weird she said it so clearly and purposefully.

After about a minute (while I was trying to figure out if she was actually telling me to go to sleep), the bedroom door slammed shut. Surprised the hell out of me. And yet not a breath of air - the curtains were completely still.

While recovering from the sudden shock of a slamming door on a dead calm night, and furious that I was now more awake than ever, my wife started to sound like she was choking. I tried to wake her, but she didn't right away. I was starting to panic, but she eventually did wake, and she sounded petrified. What she described I later found out was probably a symptom of sleep paralysis.

The next morning, we were talking about it, and she still felt uneasy about what she had dreamed. I asked her about the word she said. I didn't expect much of a response, given I'd probably misheard, remembered incorrectly, or it was simply sleep gibberish. But she looked surprised I knew the word…

It means "monster".

Given the context and the timing of the events: creepy!

Inconvenient AnonymousPermMask64

I'm borrowing a commonly recurring phrase from Waldek Mastykarz's blog with my title, because the only other thing I could come up with involved expletives. Lots of them.

If you've had to deal with SharePoint sites with anonymous access programmatically, you may have come across AnonymousPermMask64 which lets you specify what levels of access anonymous users have, if any. If your code just sets this value and moves on, it's not a big deal. But it's a tricky bugger in other cases:

  1. Once you assign a value, attempting to read the property back will cause an InvalidCast exception to be thrown (in PowerShell this is silently trapped, so you just get back null)
  2. Trying to assign another value is just as fruitless, again throwing InvalidCast in both PowerShell and .NET (e.g. maybe you're building up the permission mask with bitwise operations in a loop, or conditionally assigning permissions based on some settings)
  3. The changes are applied immediately. You don't need to do an Update() on either the SPList or SPWeb, which probably isn't what you'd want if you trap an exception later on and have to rollback, or if running some script in a test/dry-run mode.

I came across this weirdness when I was using PowerShell to automate (amongst many other things) some permission changes, and was going through the usual dance of 'if I run this command, does it actually do what I expected?' So naturally, when I assigned some permissions to a list via $list.AnonymousPermMask64 = $somePermission, and immediately wrote the property back to screen to see nothing, I got a little confused.

After much hair pulling and wondering if I'm just slowly becoming stupid (have I forgotten how to assign a value to a property‽), I came to the conclusion that something is stupid, but it's not totally me!

Here's a quick script I wrote to double-check my own sanity:

# Load the web/list, and see what the permmask is currently set to
PS> $web = get-spweb $webUrl
PS> $list=$web.Lists["Documents"]
PS> Write-Host $list.AnonymousPermMask64

# OK, nothing set. Good, let's set it to OpenItems,
# then make sure it actually took effect…
PS> $list.AnonymousPermMask64 = [Microsoft.SharePoint.SPBasePermissions]::OpenItems
PS> Write-Host $list.AnonymousPermMask64
(no output)
PS> $list.AnonymousPermMask64 -eq $null

# That… sucks. Maybe instantiate the web/list and try again?
PS> $web = get-spweb $webUrl
PS> $list=$web.Lists["Documents"]
PS> Write-Host $list.AnonymousPermMask64

# What.. the… hell. It's actually set to OpenItems??

The scariest things here are:

  1. The output is null after assigning a value
  2. Without actually doing an Update() anywhere, the new value has in fact taken hold

So at this point, a sane person might just die a little inside, accept this as another SharePoint quirk, and move on. But not me, I want to know what the hell is causing this. Reflection time.

Here's an abbreviated implementation of AnonymousPermMask64:

public SPBasePermissions AnonymousPermMask64
        return (SPBasePermissions)((long) this.m_arrListProps[21, this.m_iRow]);
        SPWeb parentWeb = this.ParentWeb;
        parentWeb.Request.SetAnonymousAccessMask (parentWeb.Url, this.InternalName, (ulong)value);
        this.m_arrListProps[21, this.m_iRow] = value;

The thing that jumps out at me was all the casting that's going on in the getter, but not much in the setter (especially given the aforementioned InvalidCast exceptions).

But why does the getter work the first time? Well, the m_arrListProps is a 2D array of object. When the properties are first pulled from the database, the value for AnonymousPermMask64 is cast as an int. And all the casts are happy. But when you call the setter, it becomes an SPBasePermissions, and all of a sudden the getter can't cast to a long (only to immediately cast back to SPBasePermissions. Sigh).

Honestly, I can't say exactly why it's failing (which is really unsatisfying). While an implicit conversion exists from uint to long, I guess .NET can't implicitly convert a SPBasePermissions enum to uint then to long, so throws a cast error.

I wrote another script using reflection magic to poke around directly in the bowels of SPList.m_arrListProps. Behold!

What I found was that if the internal value was assigned as a long rather than SPBasePermissions, everything worked nicely. Surprise, surprise.

SharePoint 2013 and anonymous RSS

Update 2015/03/08: See this post for a workaround/fix.

A client I'm doing some work at uses SharePoint 2010 for their public facing internet site, which has anonymous access enabled. Because they're such a groovy, funky, trend setting company, they use all the latest technologies… like RSS. Certain document libraries and lists allow users to subscribe via RSS, and it works well enough:

SharePoint 2010 RSS page with styling applied
The "pretty" version

But now we're implementing 2013, and one of the first things we noted was anonymous users just get a blank page when clicking the RSS link. Authenticated users get an unstyled horrible page, but that's a blog post for another day:

SharePoint 2013 RSS without styling applied
The ugly version

So the first thing I did was view source, lo and behold the RSS XML was there! So was it a problem with the XSLT maybe? I grabbed the link for the stylesheet and tried to navigate to it, only to be prompted for credentials. Sure enough, if I actually logged in, the XSLT was returned and the page loaded (albeit unstyled).

My first thought was the ViewFormPagesLockdown feature, which is now enabled by default in 2013. Sure enough, disabling that feature allowed anonymous users to load the XSLT just fine. But that also means they can view all of the other pages you generally don't want restricted viewers to see! Pages like viewlsts, dispform or AllItems.

This also raises the question: wasn't this working fine in 2010? A quick test on the existing site proved yes, it used to work just fine. So what changed? ILSpy time (I really need to donate a stack of money to those guys).

Comparing RssXsltPage.RightsRequired between the two farms, it was immediately obvious why this was broken.

SharePoint 2010:

protected override SPBasePermissions RightsRequired {
    get {
        return SPBasePermissions.Open;

SharePoint 2013:

protected override SPBasePermissions RightsRequired {
    get {
        return SPBasePermissions.ViewFormPages | SPBasePermissions.Open;

They've added ViewFormPages! I have no clue why Microsoft have done this—the ListFeed page doesn't have extra permissions. So this means users can happily pull content from the site, but oh hey don't let them get a stylesheet! /s

So after all of this, what can be done? The way the clients' site is set up, there are just a few hardcoded links around the site pointing to the RSS feed page. Rather than those links being the http:// scheme, I think I'll just change them to be the feed://. Then it'll open directly in their RSS reader, and this problem goes away. Because really, they've clicked a link for RSS, why do they need to then see another poorly formatted page with another link saying "click here to subscribe"?

Note: those screen shots above aren't from my clients site, they're from SPSDemo, and I just manually injected the old V4 CSS to get the "pretty" version.

Update 2014/05/08: I have tried to find other examples of viewlsts, you'll be denied access, which I assume is from the ViewFormPagesLockdown feature.

So maybe this is purely a bug in on-prem SharePoint 2013, or maybe Microsoft have fixed the bug and a hotfix is coming for on-prem.

Cute feature IDs

Useless tidbit: quite a few out-of-the-box SharePoint feature IDs start with "00bfea71"…

  • Out
  • Of (the)
  • Box
  • F
  • E
  • A
  • 7=T
  • (…ure)
  • 1 (because why the hell not)

PS> @(Get-SPFeature | ?{ $_.Id -match "00bfea71" }).Count

Truth be told, I have actually spent more time than I'm proud to admit trying to figure out how "71" could be an encoded form of "feat", so the GUID could read as "00b(feature)", but it's beyond me.

List of features and their GUIDs on MSDN.

Migrating to Prism

I've dabbled my toes in the open-source pool recently by making some contributions to Prism, so I figure I should probably actually use Prism for syntax highlighting on this site, right? Right?

The problem is… I'm a bit lazy. I don't want to have to change the markup in all my posts (however few there are) to be picked up by Prism instead, especially since I'd have to change everything again if I went back to the previous highlighter. Also, I haven't gotten around to contributing PowerShell support to Prism yet (again, lazy), so I'd like to be able to run both side by side easily.

What I really need is Prism to be able to recognise Auto Syntax Highlighter markup, and get in first to do the highlighting if it is a supported language.

So I wrote a little helper function to do just that; it runs before Syntax Highlighter, and converts the <pre class="brush: {language}">&hellip;</pre> style markup to the <pre><code class="language-{language}">&hellip;</code></pre> markup, but only if Prism supports that language. Here it is in all of its uncommented, Prism-highlighted glory: