Directory Services

DsCrackSpn

The DsCrackSpn function parses a service principal name (SPN) into its component strings.

DWORD DsCrackSpn(
  LPCTSTR pszSPN,
  DWORD* pcServiceClass,
  LPTSTR ServiceClass,
  DWORD* pcServiceName,
  LPTSTR ServiceName,
  DWORD* pcInstanceName,
  LPTSTR InstanceName,
  USHORT* pInstancePort
);

Parameters

pszSPN
[in] Pointer to a constant null-terminated string that contains the SPN to parse. The SPN has the following format, in which the <service class> and <instance name> components must be present and the <port number> and <service name> components are optional. The <port number> component must be a numeric string value.
<service class>/<instance name>:<port number>/<service name>
pcServiceClass
[in, out, optional] Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the ServiceClass buffer, including the terminating null character. On exit, this parameter contains the number of TCHARs in the ServiceClass string, including the terminating null character.

If this parameter is null, contains zero, or ServiceClass is null, this parameter and ServiceClass are ignored.

To obtain the number of characters required for the ServiceClass string, including the null terminator, call this function with a valid SPN, a non-null ServiceClass and this parameter set to 1.

ServiceClass
[out, optional] Pointer to a TCHAR buffer that receives a null-terminated string containing the <service class> component of the SPN. This buffer must be at least *pcServiceClass TCHARs in size. This parameter may be NULL if the service class is not required.
pcServiceName
[in, out, optional] Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the ServiceName buffer, including the terminating null character. On exit, this parameter contains the number of TCHARs in the ServiceName string, including the terminating null character.

If this parameter is null, contains zero, or ServiceName is null, this parameter and ServiceName are ignored.

To obtain the number of characters required for the ServiceName string, including the null terminator, call this function with a valid SPN, a non-null ServiceName and this parameter set to 1.

ServiceName
[out, optional] Pointer to a TCHAR buffer that receives a null-terminated string containing the <service name> component of the SPN. This buffer must be at least *pcServiceName TCHARs in size. If the <service name> component is not present in the SPN, this buffer receives the <instance name> component. This parameter may be NULL if the service name is not required.
pcInstanceName
[in, out, optional] Pointer to a DWORD value that, on entry, contains the size, in TCHARs, of the InstanceName buffer, including the terminating null character. On exit, this parameter contains the number of TCHARs in the InstanceName string, including the terminating null character.

If this parameter is null, contains zero, or InstanceName is null, this parameter and InstanceName are ignored.

To obtain the number of characters required for the InstanceName string, including the null terminator, call this function with a valid SPN, a non-null InstanceName and this parameter set to 1.

InstanceName
[out, optional] Pointer to a TCHAR buffer that receives a null-terminated string containing the <instance name> component of the SPN. This buffer must be at least *pcInstanceName TCHARs in size. This parameter may be NULL if the instance name is not required.
pInstancePort
[out, optional] Pointer to a DWORD value that receives the integer value of the <port number> component of the SPN. If the SPN does not contain a <port number> component, this parameter receives zero. This parameter may be NULL if the port number is not required.

Return Values

Returns a Win32 error code, including the following.
Return Code Description
ERROR_SUCCESS The function was successful.
ERROR_INVALID_PARAMETER pszSPN or the SPN string is not valid.
ERROR_BUFFER_OVERFLOW If any of the buffer sizes is too small, the function fails with this error and returns the required buffer size in the corresponding buffer-length parameter. To determine which buffer was too small, compare the returned sizes to the input sizes. Also, the function ignores buffers that are NULL or have a zero size on input. So, it does not return an error or required buffer size in these cases.

Example Code [C++]

The following code example demonstrates how to use DsCrackSpn to obtain the proper buffer sizes, allocate the appropriate buffers and use DsCrackSpn to parse the SPN.

//***************************************************************************
//
//  SafeCrackSpn()
//  
//  The caller must free any allocated buffers with CoTaskMemFree().
//
//***************************************************************************

HRESULT SafeCrackSpn(   LPCTSTR pszSPN, 
						LPTSTR *ppszServClass,
						LPTSTR *ppszServName,
						LPTSTR *ppszInstName,
						USHORT *pPortNum)
{
	if(!pszSPN)
	{
		return E_INVALIDARG;
}

	// Set the default values.
	if(ppszServClass)
	{
		*ppszServClass = NULL;
}
	if(ppszServName)
	{
		*ppszServName = NULL;
}
	if(ppszInstName)
	{
		*ppszInstName = NULL;
}
	if(pPortNum)
	{
		*pPortNum = 0;
}

	DWORD   dwRet;
	DWORD   dwServClassSize;
	DWORD   dwServNameSize;
	DWORD   dwInstNameSize;
	TCHAR   szTemp[1];

	dwServClassSize = 1;
	dwServNameSize = 1;
	dwInstNameSize = 1;

	// Call DsCrackSpn to get the sizes of the strings.
	dwRet = DsCrackSpn( pszSPN, 
						&dwServClassSize,
						szTemp,
						&dwServNameSize,
						szTemp,
						&dwInstNameSize,
						szTemp,
						NULL);

	if(ERROR_BUFFER_OVERFLOW == dwRet)
	{
		HRESULT hr = S_OK;
	
		// Allocate the requested buffers and call DsCrackSpn again.
		if(ppszServClass)
		{
			*ppszServClass = (LPTSTR)CoTaskMemAlloc(dwServClassSize * sizeof(TCHAR));
			if(!*ppszServClass)
			{
				hr = E_OUTOFMEMORY;
		}
	}
		if(ppszServName)
		{
			*ppszServName = (LPTSTR)CoTaskMemAlloc(dwServNameSize * sizeof(TCHAR));
			if(!*ppszServName)
			{
				hr = E_OUTOFMEMORY;
		}
	}
		if(ppszInstName)
		{
			*ppszInstName = (LPTSTR)CoTaskMemAlloc(dwInstNameSize * sizeof(TCHAR));
			if(!*ppszInstName)
			{
				hr = E_OUTOFMEMORY;
		}
	}

		if(SUCCEEDED(hr))
		{
			dwRet = DsCrackSpn( pszSPN, 
								&dwServClassSize,
								*ppszServClass,
								&dwServNameSize,
								*ppszServName,
								&dwInstNameSize,
								*ppszInstName,
								pPortNum);

			hr = HRESULT_FROM_WIN32(dwRet);
	}

		// If a failure occurs, cleanup and return an error code.
		if(FAILED(hr))
		{
			if(ppszServClass && *ppszServClass)
			{
				CoTaskMemFree(*ppszServClass);
				*ppszServClass = NULL;
		}
			if(ppszServName && *ppszServName)
			{
				CoTaskMemFree(*ppszServName);
				*ppszServName = NULL;
		}
			if(ppszInstName && *ppszInstName)
			{
				CoTaskMemFree(*ppszInstName);
				*ppszInstName = NULL;
		}
	}

		return hr;
}
	else if(ERROR_SUCCESS == dwRet)
	{
		// This should not occur, but if it does, return an error.
		return E_FAIL;
}

	// An error occurred. Return the error value.
	return HRESULT_FROM_WIN32(dwRet);
}

/**************************************************************************

	main()

**************************************************************************/

void main(void)
{
	HRESULT hr;
	LPTSTR  pszServClass;
	LPTSTR  pszServName;
	LPTSTR  pszInstName;
	USHORT  uPortNum;
	LPCTSTR pszSPN = TEXT("Service Class/Instance Name:80/Service Name");

	hr = SafeCrackSpn(  pszSPN,
						&pszServClass,
						&pszServName,
						&pszInstName,
						&uPortNum);
	if(SUCCEEDED(hr))
	{
		CoTaskMemFree(pszServClass);
		CoTaskMemFree(pszServName);
		CoTaskMemFree(pszInstName);
}
}

Requirements

Client: Included in Windows XP and Windows 2000 Professional.
Server: Included in Windows Server 2003 and Windows 2000 Server.
Redistributable: Requires Active Directory Client Extension on Windows NT 4.0 SP6a and Windows 95/98/Me.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000/XP.
Header: Declared in Ntdsapi.h.
Library: Use Ntdsapi.lib.

See Also

Domain Controller and Replication Management Functions