My SharePoint 2007 site spontaneously got into read-only mode

Just a short post this time: if you experience symptoms like:

  • no one able to edit anything on a MOSS site
  • weird permission denied errors for admins
  • buttons in the GUI disappearing

then maybe your MOSS site got into read-only mode. Happened to us today, just like that. People swear they didn’t touch anything…

Fix this from central admin.

moss-readonly

 

 

 

 

EDIT: Well, apparently I’m not the only one to experience this issue. This blog post describes the exact situation (which is obviously related to stsadm backups) and also offers a possible solution – adding the –NoSiteLock switch to your backup task.

Restoring Sharepoint content database from backup

A small script to quickly restore a Sharepoint 2007 content database from backup:

USE master
GO

ALTER DATABASE SITE_WSS_Content
SET SINGLE_USER WITH
ROLLBACK AFTER 5
GO

RESTORE DATABASE SITE_WSS_Content
FROM DISK = 'path_to_backup\SITE_WSS_Content_backup_201201122000.bak'
WITH REPLACE
GO

ALTER DATABASE SITE_WSS_Content
SET MULTI_USER
GO

Get back your Sharepoint 2007 site manager context menu!

Today my customer’s site manager on their Sharepoint 2007 site went bananas. The context menu used to configure list items shrunk to four items from eight.

mossmenu

Apparently this is a known bug in MOSS that’s supposedly been fixed in a cummulative update from 2009, but hey, here it was. In short the RenderXMLUsingPattern attribute on a Field definition gets lost and has to be set back to TRUE.

I’ve made a little tool to do just that. The tool is attached in the archive below. Call it like this:

MossMenuFix.exe http://my.site.com/web Pages

where http://my.site.com/web is the web address and Pages is the name of the list. More info on this is available here.

MossMenuFix.zip

Deleting TFS 2010 work items

This is how to do this:

  • Open a command prompt, change to your Visual Studio 2010 dir (usually “c:\Program Files\Microsoft Visual Studio 10.0\Common 7\IDE”).
  • Execute this command
    witadmin.exe destroywi /id:123 /collection:http://tfs01:8080/tfs/DefaultCollection

    replacing 123 with your work item id and the http://tfs01:8080/tfs/DefaultCollection with your TFS collection url.

DTS_E_CANNOTACQUIRECONNECTIONFROMCONNECTIONMANAGER when executing a SSIS package

The DTS_E_CANNOTACQUIRECONNECTIONFROMCONNECTIONMANAGER ierror can sometimes be resolved by verifying that the called stored procedure exists and that the executing user account has access to it.

Thank you Microsoft for inventing world’s longest constant name and thus screwing up my WordPress layout!

When IIS 6 doesn’t want to let you in – 401 Access Denied

Had a little fight with my local IIS 6 running on a local user account using integrated authentication. It just wouldn’t let me in, no matter what rights I assigned to the user and to the directory.

Apparently this is a known issue documented here which can be resolved by setting a metabase key with the command below.

cscript adsutil.vbs set w3svc/NTAuthenticationProviders "NTLM"

P/Invoke and LoadLibrary / GetProcAddress

A little snippet I wrote while trying to use LoadLibrary/GetProcAddress to call functions and get variable values that are exported by an unmanaged dll with P/Invoke.

extern "C" __declspec(dllexport) const char* _Version = "0.1";

extern "C" __declspec(dllexport) const char* GetMyVersion(void)
{
	return _Version;
}
[TestMethod]
public void TestPinvoke()
{
		IntPtr lib = LoadLibrary(@"C:\Documents and Settings\Administrator\My Documents\Visual Studio 2010\Projects\TestWinDll\Debug\TestWinDll.dll");
		if(lib == IntPtr.Zero)
				throw new Win32Exception(Marshal.GetLastWin32Error());

		IntPtr procAddress = GetProcAddress(lib, "GetMyVersion");
		var gmv = (GetMyVersion)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(GetMyVersion));
		var ver = gmv();

		procAddress = Marshal.ReadIntPtr(GetProcAddress(lib, "_Version"));
		var ver2 = Marshal.PtrToStringAnsi(procAddress);

		if(!FreeLibrary(lib))
				throw new Win32Exception(Marshal.GetLastWin32Error());
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate String GetMyVersion();

[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeLibrary(IntPtr hModule);

Real-time CRL validation for X.509 certificates in .NET

This is a continuation of my post on
Avoiding X.509 chain policy caching when using WCF with certificate security.

I wrote the code below to implement certificate validation against a published CRL in real-time. The default mechanism uses a cache / validity period, which might be impractical when you want to deny a revoked certificate at once.

The code looks for a CRL link in the provided certificate and uses it to download the base CRL. It then validates the certificate against the CRL and also retrieves the delta CRL (referenced by the base CRL) and validates against that as well.

I P/Invoked crypto32 API because .NET doesn’t have the necessary classes for handling CRLs.

using System;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;

namespace My.IdentityModel
{
    /// <summary>
    /// x509 certificate utilities
    /// Richard Ginzburg - richard@ginzburgconsulting.com
    /// </summary>
    public static class CertUtil
    {
        private const string CERT_CRL_EXTENSION = "2.5.29.31";
        private const string CRL_CRL_EXTENSION = "2.5.29.46";

        public static bool IsCertificateInCrl(X509Certificate2 cert)
        {
            try
            {
                string certCrlUrl = GetBaseCrlUrl(cert);
                return IsCertificateInCrl(cert, certCrlUrl);
            }
            catch
            {
                return false;
            }
        }

        public static bool IsCertificateInCrl(X509Certificate2 cert, string url)
        {
            WebClient wc = new WebClient();
            byte[] rgRawCrl = wc.DownloadData(url);

            IntPtr phCertStore = IntPtr.Zero;
            IntPtr pvContext = IntPtr.Zero;
            GCHandle hCrlData = new GCHandle();
            GCHandle hCryptBlob = new GCHandle();
            try
            {
                hCrlData = GCHandle.Alloc(rgRawCrl, GCHandleType.Pinned);
                WinCrypt32.CRYPTOAPI_BLOB stCryptBlob;
                stCryptBlob.cbData = rgRawCrl.Length;
                stCryptBlob.pbData = hCrlData.AddrOfPinnedObject();
                hCryptBlob = GCHandle.Alloc(stCryptBlob, GCHandleType.Pinned);

                if (!WinCrypt32.CryptQueryObject(
                WinCrypt32.CERT_QUERY_OBJECT_BLOB,
                hCryptBlob.AddrOfPinnedObject(),
                WinCrypt32.CERT_QUERY_CONTENT_FLAG_CRL,
                WinCrypt32.CERT_QUERY_FORMAT_FLAG_BINARY,
                0,
                IntPtr.Zero,
                IntPtr.Zero,
                IntPtr.Zero,
                ref phCertStore,
                IntPtr.Zero,
                ref pvContext
                ))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                WinCrypt32.CRL_CONTEXT stCrlContext = (WinCrypt32.CRL_CONTEXT)Marshal.PtrToStructure(pvContext, typeof(WinCrypt32.CRL_CONTEXT));
                WinCrypt32.CRL_INFO stCrlInfo = (WinCrypt32.CRL_INFO)Marshal.PtrToStructure(stCrlContext.pCrlInfo, typeof(WinCrypt32.CRL_INFO));

                if (IsCertificateInCrl(cert, stCrlInfo))
                {
                    return true;
                }
                else 
                {
                    url = GetDeltaCrlUrl(stCrlInfo);
                    if (!string.IsNullOrEmpty(url))
                    {
                        return IsCertificateInCrl(cert, url);
                    }
                }
            }
            finally
            {
                if (hCrlData.IsAllocated) hCrlData.Free();
                if (hCryptBlob.IsAllocated) hCryptBlob.Free();
                if (!pvContext.Equals(IntPtr.Zero))
                {
                    WinCrypt32.CertFreeCRLContext(pvContext);
                }
            }

            return false;
        }

        private static bool IsCertificateInCrl(X509Certificate2 cert, WinCrypt32.CRL_INFO stCrlInfo)
        {
            IntPtr rgCrlEntry = stCrlInfo.rgCRLEntry;

            for (int i = 0; i < stCrlInfo.cCRLEntry; i++)
            {
                string serial = string.Empty;
                WinCrypt32.CRL_ENTRY stCrlEntry = (WinCrypt32.CRL_ENTRY)Marshal.PtrToStructure(rgCrlEntry, typeof(WinCrypt32.CRL_ENTRY));

                IntPtr pByte = stCrlEntry.SerialNumber.pbData;
                for (int j = 0; j < stCrlEntry.SerialNumber.cbData; j++)
                {
                    Byte bByte = Marshal.ReadByte(pByte);
                    serial = bByte.ToString("X").PadLeft(2, '0') + serial;
                    pByte = (IntPtr)((Int32)pByte + Marshal.SizeOf(typeof(Byte)));
                }
                if (cert.SerialNumber == serial)
                {
                    return true;
                }
                rgCrlEntry = (IntPtr)((Int32)rgCrlEntry + Marshal.SizeOf(typeof(WinCrypt32.CRL_ENTRY)));
            }
            return false;
        }

        private static string GetBaseCrlUrl(X509Certificate2 cert)
        {
            try
            {
                return (from X509Extension extension in cert.Extensions
                        where extension.Oid.Value.Equals(CERT_CRL_EXTENSION)
                        select GetCrlUrlFromExtension(extension)).Single();
            }
            catch
            {
                return null;
            }
        }

        private static string GetDeltaCrlUrl(WinCrypt32.CRL_INFO stCrlInfo)
        {
            IntPtr rgExtension = stCrlInfo.rgExtension;
            X509Extension deltaCrlExtension = null;

            for (int i = 0; i < stCrlInfo.cExtension; i++)
            {
                WinCrypt32.CERT_EXTENSION stCrlExt = (WinCrypt32.CERT_EXTENSION)Marshal.PtrToStructure(rgExtension, typeof(WinCrypt32.CERT_EXTENSION));

                if (stCrlExt.Value.pbData != IntPtr.Zero && stCrlExt.pszObjId == CRL_CRL_EXTENSION)
                {
                    byte[] rawData = new byte[stCrlExt.Value.cbData];
                    Marshal.Copy(stCrlExt.Value.pbData, rawData, 0, rawData.Length);
                    deltaCrlExtension = new X509Extension(stCrlExt.pszObjId, rawData, stCrlExt.fCritical);
                    break;
                }

                rgExtension = (IntPtr)((Int32)rgExtension + Marshal.SizeOf(typeof(WinCrypt32.CERT_EXTENSION)));
            }
            if (deltaCrlExtension == null)
            {
                return null;
            }
            return GetCrlUrlFromExtension(deltaCrlExtension);
        }

        private static string GetCrlUrlFromExtension(X509Extension extension)
        {
            try
            {
                Regex rx = new Regex("http://.*crl");
                string raw = new AsnEncodedData(extension.Oid, extension.RawData).Format(false);
                return rx.Match(raw).Value;
            }
            catch
            {
                return null;
            }
        }
    }
}

The custom validator is below

using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace My.IdentityModel
{
    /// <summary>
    /// Custom x509 certificate validator
    /// Richard Ginzburg - richard@ginzburgconsulting.com
    /// </summary>
    public class MyX509Validator : X509CertificateValidator
    {
        public override void Validate(X509Certificate2 certificate)
        {
            var myChainPolicy = new X509ChainPolicy
                                    {
                                        RevocationMode = X509RevocationMode.Online,
                                        RevocationFlag = X509RevocationFlag.EntireChain,
                                        VerificationFlags = X509VerificationFlags.NoFlag,
                                        UrlRetrievalTimeout = new TimeSpan(0, 0, 10),
                                        VerificationTime = DateTime.Now
                                    };
            var chain = new X509Chain(true) {ChainPolicy = myChainPolicy};

            try
            {
                if (!chain.Build(certificate))
                    throw new SecurityTokenValidationException("Certificate validation failed when building chain");
                if (CertUtil.IsCertificateInCrl(certificate))
                    throw new SecurityTokenValidationException("Certificate is revoked by CRL");
            }
            catch (CryptographicException e)
            {
                throw new SecurityTokenValidationException("Certificate validation failed when building chain, " + e);
            }
        }
    }
}

and finally some crypt32 API

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace My.IdentityModel
{
    public static class WinCrypt32
    {
        #region APIs

        [DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean CryptQueryObject(
            Int32 dwObjectType,
            IntPtr pvObject, 
            Int32 dwExpectedContentTypeFlags,
            Int32 dwExpectedFormatTypeFlags,
            Int32 dwFlags,
            IntPtr pdwMsgAndCertEncodingType,
            IntPtr pdwContentType,
            IntPtr pdwFormatType,
            ref IntPtr phCertStore,
            IntPtr phMsg,
            ref IntPtr ppvContext
            );

        [DllImport("CRYPT32.DLL", EntryPoint = "CertFreeCRLContext", SetLastError = true)]
        public static extern Boolean CertFreeCRLContext(
            IntPtr pCrlContext
        );

        [DllImport("CRYPT32.DLL", EntryPoint = "CertNameToStr", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Int32 CertNameToStr(
            Int32 dwCertEncodingType,
            ref CRYPTOAPI_BLOB pName,
            Int32 dwStrType,
            StringBuilder psz,
            Int32 csz
        );

        [DllImport("CRYPT32.DLL", EntryPoint = "CertFindExtension", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CertFindExtension(
            [MarshalAs(UnmanagedType.LPStr)]String pszObjId,
            Int32 cExtensions,
            IntPtr rgExtensions
        );

        [DllImport("CRYPT32.DLL", EntryPoint = "CryptFormatObject", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean CryptFormatObject(
            Int32 dwCertEncodingType,
            Int32 dwFormatType,
            Int32 dwFormatStrType,
            IntPtr pFormatStruct,
            [MarshalAs(UnmanagedType.LPStr)]String lpszStructType,
            IntPtr pbEncoded,
            Int32 cbEncoded,
            StringBuilder pbFormat,
            ref Int32 pcbFormat
        );

        #endregion APIs

        #region Structs
        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPT_OBJID_BLOB
        {
            public uint cbData;
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
            public byte[] pbData;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct CERT_PUBLIC_KEY_INFO
        {
            public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
            public CRYPTOAPI_BLOB PublicKey;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct CERT_EXTENSION
        {
            [MarshalAs(UnmanagedType.LPStr)]
            public string pszObjId;
            public bool fCritical;
            public CRYPTOAPI_BLOB Value;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CERT_CONTEXT
        {
            public uint dwCertEncodingType;
            public IntPtr pbCertEncoded;
            public uint cbCertEncoded;
            public IntPtr pCertInfo;
            public IntPtr hCertStore;
        }

        public struct CERT_INFO
        {
            public int dwVersion;
            public CRYPTOAPI_BLOB SerialNumber;
            public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
            public CRYPTOAPI_BLOB Issuer;
            public FILETIME NotBefore;
            public FILETIME NotAfter;
            public CRYPTOAPI_BLOB Subject;
            public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
            public CRYPTOAPI_BLOB IssuerUniqueId;
            public CRYPTOAPI_BLOB SubjectUniqueId;
            public int cExtension;
            public CERT_EXTENSION rgExtension;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRL_CONTEXT
        {
            public Int32 dwCertEncodingType;
            public IntPtr pbCrlEncoded;
            public Int32 cbCrlEncoded;
            public IntPtr pCrlInfo;
            public IntPtr hCertStore;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRL_INFO
        {
            public Int32 dwVersion;
            public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
            public CRYPTOAPI_BLOB Issuer;
            public FILETIME ThisUpdate;
            public FILETIME NextUpdate;
            public Int32 cCRLEntry;
            public IntPtr rgCRLEntry;
            public Int32 cExtension;
            public IntPtr rgExtension;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPT_ALGORITHM_IDENTIFIER
        {
            [MarshalAs(UnmanagedType.LPStr)]
            public String pszObjId;
            public CRYPTOAPI_BLOB Parameters;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPTOAPI_BLOB
        {
            public Int32 cbData;
            public IntPtr pbData;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct FILETIME
        {
            public Int32 dwLowDateTime;
            public Int32 dwHighDateTime;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRL_ENTRY
        {
            public CRYPTOAPI_BLOB SerialNumber;
            public FILETIME RevocationDate;
            public Int32 cExtension;
            public IntPtr rgExtension;
        }

        #endregion Structs

        #region Consts

        public const Int32 CERT_QUERY_OBJECT_FILE = 0x00000001;
        public const Int32 CERT_QUERY_OBJECT_BLOB = 0x00000002;
        public const Int32 CERT_QUERY_CONTENT_CRL = 3;
        public const Int32 CERT_QUERY_CONTENT_FLAG_CRL = 1 << CERT_QUERY_CONTENT_CRL;
        public const Int32 CERT_QUERY_FORMAT_BINARY = 1;
        public const Int32 CERT_QUERY_FORMAT_BASE64_ENCODED = 2;
        public const Int32 CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3;
        public const Int32 CERT_QUERY_FORMAT_FLAG_BINARY = 1 << CERT_QUERY_FORMAT_BINARY;
        public const Int32 CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = 1 << CERT_QUERY_FORMAT_BASE64_ENCODED;
        public const Int32 CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = 1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED;
        public const Int32 CERT_QUERY_FORMAT_FLAG_ALL = CERT_QUERY_FORMAT_FLAG_BINARY | CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED;

        public const Int32 X509_ASN_ENCODING = 0x00000001;
        public const Int32 PKCS_7_ASN_ENCODING = 0x00010000;

        public const Int32 X509_NAME = 7;

        public const Int32 CERT_SIMPLE_NAME_STR = 1;
        public const Int32 CERT_OID_NAME_STR = 2;
        public const Int32 CERT_X500_NAME_STR = 3;

        public const String szOID_CRL_REASON_CODE = "2.5.29.21";

        public enum Disposition : uint
        {
            CERT_STORE_ADD_NEW = 1,
            CERT_STORE_ADD_USE_EXISTING = 2,
            CERT_STORE_ADD_REPLACE_EXISTING = 3,
            CERT_STORE_ADD_ALWAYS = 4,
            CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES = 5,
            CERT_STORE_ADD_NEWER = 6,
            CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES = 7,
        }

        [Flags]
        public enum FindFlags : int
        {
            CRL_FIND_ISSUED_BY_AKI_FLAG = 0x1,
            CRL_FIND_ISSUED_BY_SIGNATURE_FLAG = 0x2,
            CRL_FIND_ISSUED_BY_DELTA_FLAG = 0x4,
            CRL_FIND_ISSUED_BY_BASE_FLAG = 0x8,
        }

        public enum FindType : int
        {
            CRL_FIND_ANY = 0,
            CRL_FIND_ISSUED_BY = 1,
            CRL_FIND_EXISTING = 2,
            CRL_FIND_ISSUED_FOR = 3
        }

        #endregion
    }
}

Setting SMSC number on an Android phone

To set the SMS center number on a Samsung Galaxy SII phone do the following:

Open the dialer and enter *#*#4636#*#*. You will be greeted with a nice phone settings menu, one of those settings is named SMSC and is the SMS center number in PDU format. The format is described here along with a nice online converter, but the part we are interested in is the beginning.

For the Swedish provider Telenor the number should be 07916407080007F8 as the phone number to the sms center is +46708000708.

  • the 07 here is the length of information in number of octets.
  • the 91 signifies “international format”, basically a +.
  • The rest is the phone number, in this case 6407080007F8 as the phone number to the sms center is +46708000708, in decimal semi-octets. Because the total number of digits in the phone number is odd an F is added.

I’ve color-coded the number to make it easier to understand the whole decimal semi-octets stuff. If I did help you – leave a comment. 😉

More information on the PDU format is available here.