* PURPOSE: Service control manager functions
* PROGRAMMER: Emanuele Aliberti
* Eric Kohl
+ * Pierre Schweitzer
*/
/* INCLUDES ******************************************************************/
#include <advapi32.h>
-WINE_DEFAULT_DEBUG_CHANNEL(advapi_service);
+WINE_DEFAULT_DEBUG_CHANNEL(advapi);
+NTSTATUS
+WINAPI
+SystemFunction004(
+ const struct ustring *in,
+ const struct ustring *key,
+ struct ustring *out);
+
+NTSTATUS
+WINAPI
+SystemFunction028(
+ IN PVOID ContextHandle,
+ OUT LPBYTE SessionKey);
/* FUNCTIONS *****************************************************************/
{
handle_t hBinding = NULL;
RPC_CSTR pszStringBinding;
- RPC_STATUS Status;
+ RPC_STATUS status;
- TRACE("SVCCTL_HANDLEA_bind()\n");
+ TRACE("SVCCTL_HANDLEA_bind(%s)\n",
+ debugstr_a(szMachineName));
- Status = RpcStringBindingComposeA(NULL,
+ status = RpcStringBindingComposeA(NULL,
(RPC_CSTR)"ncacn_np",
(RPC_CSTR)szMachineName,
(RPC_CSTR)"\\pipe\\ntsvcs",
NULL,
&pszStringBinding);
- if (Status != RPC_S_OK)
+ if (status != RPC_S_OK)
{
- ERR("RpcStringBindingCompose returned 0x%x\n", Status);
+ ERR("RpcStringBindingCompose returned 0x%x\n", status);
return NULL;
}
/* Set the binding handle that will be used to bind to the server. */
- Status = RpcBindingFromStringBindingA(pszStringBinding,
+ status = RpcBindingFromStringBindingA(pszStringBinding,
&hBinding);
- if (Status != RPC_S_OK)
+ if (status != RPC_S_OK)
{
- ERR("RpcBindingFromStringBinding returned 0x%x\n", Status);
+ ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
}
- Status = RpcStringFreeA(&pszStringBinding);
- if (Status != RPC_S_OK)
+ status = RpcStringFreeA(&pszStringBinding);
+ if (status != RPC_S_OK)
{
- ERR("RpcStringFree returned 0x%x\n", Status);
+ ERR("RpcStringFree returned 0x%x\n", status);
}
return hBinding;
SVCCTL_HANDLEA_unbind(SVCCTL_HANDLEA szMachineName,
handle_t hBinding)
{
- RPC_STATUS Status;
+ RPC_STATUS status;
- TRACE("SVCCTL_HANDLEA_unbind()\n");
+ TRACE("SVCCTL_HANDLEA_unbind(%s %p)\n",
+ debugstr_a(szMachineName), hBinding);
- Status = RpcBindingFree(&hBinding);
- if (Status != RPC_S_OK)
+ status = RpcBindingFree(&hBinding);
+ if (status != RPC_S_OK)
{
- ERR("RpcBindingFree returned 0x%x\n", Status);
+ ERR("RpcBindingFree returned 0x%x\n", status);
}
}
{
handle_t hBinding = NULL;
RPC_WSTR pszStringBinding;
- RPC_STATUS Status;
+ RPC_STATUS status;
- TRACE("SVCCTL_HANDLEW_bind()\n");
+ TRACE("SVCCTL_HANDLEW_bind(%s)\n",
+ debugstr_w(szMachineName));
- Status = RpcStringBindingComposeW(NULL,
+ status = RpcStringBindingComposeW(NULL,
L"ncacn_np",
szMachineName,
L"\\pipe\\ntsvcs",
NULL,
&pszStringBinding);
- if (Status != RPC_S_OK)
+ if (status != RPC_S_OK)
{
- ERR("RpcStringBindingCompose returned 0x%x\n", Status);
+ ERR("RpcStringBindingCompose returned 0x%x\n", status);
return NULL;
}
/* Set the binding handle that will be used to bind to the server. */
- Status = RpcBindingFromStringBindingW(pszStringBinding,
+ status = RpcBindingFromStringBindingW(pszStringBinding,
&hBinding);
- if (Status != RPC_S_OK)
+ if (status != RPC_S_OK)
{
- ERR("RpcBindingFromStringBinding returned 0x%x\n", Status);
+ ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
}
- Status = RpcStringFreeW(&pszStringBinding);
- if (Status != RPC_S_OK)
+ status = RpcStringFreeW(&pszStringBinding);
+ if (status != RPC_S_OK)
{
- ERR("RpcStringFree returned 0x%x\n", Status);
+ ERR("RpcStringFree returned 0x%x\n", status);
}
return hBinding;
SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW szMachineName,
handle_t hBinding)
{
- RPC_STATUS Status;
+ RPC_STATUS status;
- TRACE("SVCCTL_HANDLEW_unbind()\n");
+ TRACE("SVCCTL_HANDLEW_unbind(%s %p)\n",
+ debugstr_w(szMachineName), hBinding);
- Status = RpcBindingFree(&hBinding);
- if (Status != RPC_S_OK)
+ status = RpcBindingFree(&hBinding);
+ if (status != RPC_S_OK)
{
- ERR("RpcBindingFree returned 0x%x\n", Status);
+ ERR("RpcBindingFree returned 0x%x\n", status);
}
}
-/* HACK: because of a problem with rpcrt4, rpcserver is hacked to return 6 for ERROR_SERVICE_DOES_NOT_EXIST */
DWORD
ScmRpcStatusToWinError(RPC_STATUS Status)
{
+ TRACE("ScmRpcStatusToWinError(%lx)\n",
+ Status);
+
switch (Status)
{
case STATUS_ACCESS_VIOLATION:
}
+static
+DWORD
+ScmEncryptPassword(
+ _In_ PVOID ContextHandle,
+ _In_ PCWSTR pClearTextPassword,
+ _Out_ PBYTE *pEncryptedPassword,
+ _Out_ PDWORD pEncryptedPasswordSize)
+{
+ struct ustring inData, keyData, outData;
+ BYTE SessionKey[16];
+ PBYTE pBuffer;
+ NTSTATUS Status;
+
+ /* Get the session key */
+ Status = SystemFunction028(ContextHandle,
+ SessionKey);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("SystemFunction028 failed (Status 0x%08lx)\n", Status);
+ return RtlNtStatusToDosError(Status);
+ }
+
+ inData.Length = (wcslen(pClearTextPassword) + 1) * sizeof(WCHAR);
+ inData.MaximumLength = inData.Length;
+ inData.Buffer = (unsigned char *)pClearTextPassword;
+
+ keyData.Length = sizeof(SessionKey);
+ keyData.MaximumLength = keyData.Length;
+ keyData.Buffer = SessionKey;
+
+ outData.Length = 0;
+ outData.MaximumLength = 0;
+ outData.Buffer = NULL;
+
+ /* Get the required buffer size */
+ Status = SystemFunction004(&inData,
+ &keyData,
+ &outData);
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ ERR("SystemFunction004 failed (Status 0x%08lx)\n", Status);
+ return RtlNtStatusToDosError(Status);
+ }
+
+ /* Allocate a buffer for the encrypted password */
+ pBuffer = HeapAlloc(GetProcessHeap(), 0, outData.Length);
+ if (pBuffer == NULL)
+ return ERROR_OUTOFMEMORY;
+
+ outData.MaximumLength = outData.Length;
+ outData.Buffer = pBuffer;
+
+ /* Encrypt the password */
+ Status = SystemFunction004(&inData,
+ &keyData,
+ &outData);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("SystemFunction004 failed (Status 0x%08lx)\n", Status);
+ HeapFree(GetProcessHeap(), 0, pBuffer);
+ return RtlNtStatusToDosError(Status);
+ }
+
+ *pEncryptedPassword = outData.Buffer;
+ *pEncryptedPasswordSize = outData.Length;
+
+ return ERROR_SUCCESS;
+}
+
+
/**********************************************************************
* ChangeServiceConfig2A
*
SC_RPC_CONFIG_INFOA Info;
DWORD dwError;
- TRACE("ChangeServiceConfig2A()\n");
+ TRACE("ChangeServiceConfig2A(%p %lu %p)\n",
+ hService, dwInfoLevel, lpInfo);
if (lpInfo == NULL) return TRUE;
SC_RPC_CONFIG_INFOW Info;
DWORD dwError;
- TRACE("ChangeServiceConfig2W()\n");
+ TRACE("ChangeServiceConfig2W(%p %lu %p)\n",
+ hService, dwInfoLevel, lpInfo);
if (lpInfo == NULL) return TRUE;
DWORD dwDependenciesLength = 0;
SIZE_T cchLength;
LPCSTR lpStr;
- DWORD dwPasswordLength = 0;
+ DWORD dwPasswordSize = 0;
LPWSTR lpPasswordW = NULL;
LPBYTE lpEncryptedPassword = NULL;
- TRACE("ChangeServiceConfigA()\n");
+ TRACE("ChangeServiceConfigA(%p %lu %lu %lu %s %s %p %s %s %s %s)\n",
+ hService, dwServiceType, dwStartType, dwErrorControl, debugstr_a(lpBinaryPathName),
+ debugstr_a(lpLoadOrderGroup), lpdwTagId, debugstr_a(lpDependencies),
+ debugstr_a(lpServiceStartName), debugstr_a(lpPassword), debugstr_a(lpDisplayName));
/* Calculate the Dependencies length*/
if (lpDependencies != NULL)
lpPasswordW,
(int)(strlen(lpPassword) + 1));
- /* FIXME: Encrypt the password */
- lpEncryptedPassword = (LPBYTE)lpPasswordW;
- dwPasswordLength = (wcslen(lpPasswordW) + 1) * sizeof(WCHAR);
+ /* Encrypt the unicode password */
+ dwError = ScmEncryptPassword(hService,
+ lpPasswordW,
+ &lpEncryptedPassword,
+ &dwPasswordSize);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
RpcTryExcept
dwDependenciesLength,
(LPSTR)lpServiceStartName,
lpEncryptedPassword,
- dwPasswordLength,
+ dwPasswordSize,
(LPSTR)lpDisplayName);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
}
RpcEndExcept;
+done:
if (lpPasswordW != NULL)
+ {
+ /* Wipe and release the password buffers */
+ SecureZeroMemory(lpPasswordW, (wcslen(lpPasswordW) + 1) * sizeof(WCHAR));
HeapFree(GetProcessHeap(), 0, lpPasswordW);
+ if (lpEncryptedPassword != NULL)
+ {
+ SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
+ HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
+ }
+ }
+
if (dwError != ERROR_SUCCESS)
{
TRACE("RChangeServiceConfigA() failed (Error %lu)\n", dwError);
DWORD dwDependenciesLength = 0;
SIZE_T cchLength;
LPCWSTR lpStr;
- DWORD dwPasswordLength = 0;
+ DWORD dwPasswordSize = 0;
LPBYTE lpEncryptedPassword = NULL;
- TRACE("ChangeServiceConfigW()\n");
+ TRACE("ChangeServiceConfigW(%p %lu %lu %lu %s %s %p %s %s %s %s)\n",
+ hService, dwServiceType, dwStartType, dwErrorControl, debugstr_w(lpBinaryPathName),
+ debugstr_w(lpLoadOrderGroup), lpdwTagId, debugstr_w(lpDependencies),
+ debugstr_w(lpServiceStartName), debugstr_w(lpPassword), debugstr_w(lpDisplayName));
/* Calculate the Dependencies length*/
if (lpDependencies != NULL)
if (lpPassword != NULL)
{
- /* FIXME: Encrypt the password */
- lpEncryptedPassword = (LPBYTE)lpPassword;
- dwPasswordLength = (wcslen(lpPassword) + 1) * sizeof(WCHAR);
+ dwError = ScmEncryptPassword(hService,
+ lpPassword,
+ &lpEncryptedPassword,
+ &dwPasswordSize);
+ if (dwError != ERROR_SUCCESS)
+ {
+ ERR("ScmEncryptPassword failed (Error %lu)\n", dwError);
+ goto done;
+ }
}
RpcTryExcept
dwDependenciesLength,
(LPWSTR)lpServiceStartName,
lpEncryptedPassword,
- dwPasswordLength,
+ dwPasswordSize,
(LPWSTR)lpDisplayName);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
}
RpcEndExcept;
+done:
+ if (lpEncryptedPassword != NULL)
+ {
+ /* Wipe and release the password buffer */
+ SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
+ HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
+ }
+
if (dwError != ERROR_SUCCESS)
{
TRACE("RChangeServiceConfigW() failed (Error %lu)\n", dwError);
DWORD dwError;
SIZE_T cchLength;
LPCSTR lpStr;
- DWORD dwPasswordLength = 0;
+ DWORD dwPasswordSize = 0;
LPWSTR lpPasswordW = NULL;
LPBYTE lpEncryptedPassword = NULL;
- TRACE("CreateServiceA(%p %s %s)\n",
- hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
+ TRACE("CreateServiceA(%p %s %s %lx %lu %lu %lu %s %s %p %s %s %s)\n",
+ hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName),
+ dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
+ debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup), lpdwTagId,
+ debugstr_a(lpDependencies), debugstr_a(lpServiceStartName), debugstr_a(lpPassword));
if (!hSCManager)
{
lpPasswordW,
(int)(strlen(lpPassword) + 1));
- /* FIXME: Encrypt the password */
- lpEncryptedPassword = (LPBYTE)lpPasswordW;
- dwPasswordLength = (wcslen(lpPasswordW) + 1) * sizeof(WCHAR);
+ /* Encrypt the password */
+ dwError = ScmEncryptPassword(hSCManager,
+ lpPasswordW,
+ &lpEncryptedPassword,
+ &dwPasswordSize);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
RpcTryExcept
dwDependenciesLength,
(LPSTR)lpServiceStartName,
lpEncryptedPassword,
- dwPasswordLength,
+ dwPasswordSize,
(SC_RPC_HANDLE *)&hService);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
}
RpcEndExcept;
+done:
if (lpPasswordW != NULL)
+ {
+ /* Wipe and release the password buffers */
+ SecureZeroMemory(lpPasswordW, (wcslen(lpPasswordW) + 1) * sizeof(WCHAR));
HeapFree(GetProcessHeap(), 0, lpPasswordW);
+ if (lpEncryptedPassword != NULL)
+ {
+ SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
+ HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
+ }
+ }
+
SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
DWORD dwError;
SIZE_T cchLength;
LPCWSTR lpStr;
- DWORD dwPasswordLength = 0;
+ DWORD dwPasswordSize = 0;
LPBYTE lpEncryptedPassword = NULL;
- TRACE("CreateServiceW(%p %s %s)\n",
- hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
+ TRACE("CreateServiceW(%p %s %s %lx %lu %lu %lu %s %s %p %s %s %s)\n",
+ hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName),
+ dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
+ debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup), lpdwTagId,
+ debugstr_w(lpDependencies), debugstr_w(lpServiceStartName), debugstr_w(lpPassword));
if (!hSCManager)
{
if (lpPassword != NULL)
{
- /* FIXME: Encrypt the password */
- lpEncryptedPassword = (LPBYTE)lpPassword;
- dwPasswordLength = (wcslen(lpPassword) + 1) * sizeof(WCHAR);
+ /* Encrypt the password */
+ dwError = ScmEncryptPassword(hSCManager,
+ lpPassword,
+ &lpEncryptedPassword,
+ &dwPasswordSize);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
RpcTryExcept
dwDependenciesLength,
lpServiceStartName,
lpEncryptedPassword,
- dwPasswordLength,
+ dwPasswordSize,
(SC_RPC_HANDLE *)&hService);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
}
RpcEndExcept;
+done:
+ if (lpEncryptedPassword != NULL)
+ {
+ /* Wipe and release the password buffers */
+ SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
+ HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
+ }
+
SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
DWORD dwError;
DWORD dwCount;
- TRACE("EnumDependentServicesA()\n");
+ TRACE("EnumDependentServicesA(%p %lu %p %lu %p %p)\n",
+ hService, dwServiceState, lpServices, cbBufSize,
+ pcbBytesNeeded, lpServicesReturned);
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSA))
{
DWORD dwError;
DWORD dwCount;
- TRACE("EnumDependentServicesW()\n");
+ TRACE("EnumDependentServicesW(%p %lu %p %lu %p %p)\n",
+ hService, dwServiceState, lpServices, cbBufSize,
+ pcbBytesNeeded, lpServicesReturned);
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
{
DWORD dwError;
DWORD dwCount;
- TRACE("EnumServiceGroupW()\n");
+ TRACE("EnumServiceGroupW(%p %lu %lu %p %lu %p %p %p %s)\n",
+ hSCManager, dwServiceType, dwServiceState, lpServices,
+ cbBufSize, pcbBytesNeeded, lpServicesReturned,
+ lpResumeHandle, debugstr_w(lpGroup));
if (!hSCManager)
{
DWORD dwError;
DWORD dwCount;
- TRACE("EnumServicesStatusA()\n");
+ TRACE("EnumServicesStatusA(%p %lu %lu %p %lu %p %p %p)\n",
+ hSCManager, dwServiceType, dwServiceState, lpServices,
+ cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
if (!hSCManager)
{
DWORD dwError;
DWORD dwCount;
- TRACE("EnumServicesStatusW()\n");
+ TRACE("EnumServicesStatusW(%p %lu %lu %p %lu %p %p %p)\n",
+ hSCManager, dwServiceType, dwServiceState, lpServices,
+ cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
if (!hSCManager)
{
DWORD dwError;
DWORD dwCount;
- TRACE("EnumServicesStatusExA()\n");
+ TRACE("EnumServicesStatusExA(%p %lu %lu %p %lu %p %p %p %s)\n",
+ hSCManager, dwServiceType, dwServiceState, lpServices,
+ cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle,
+ debugstr_a(pszGroupName));
if (InfoLevel != SC_ENUM_PROCESS_INFO)
{
DWORD dwError;
DWORD dwCount;
- TRACE("EnumServicesStatusExW()\n");
+ TRACE("EnumServicesStatusExW(%p %lu %lu %p %lu %p %p %p %s)\n",
+ hSCManager, dwServiceType, dwServiceState, lpServices,
+ cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle,
+ debugstr_w(pszGroupName));
if (InfoLevel != SC_ENUM_PROCESS_INFO)
{
return FALSE;
}
+ /*
+ * NOTE: A size of 1 character would be enough, but tests show that
+ * Windows returns 2 characters instead, certainly due to a WCHAR/bytes
+ * mismatch in their code.
+ */
if (!lpDisplayName || *lpcchBuffer < sizeof(WCHAR))
{
lpNameBuffer = szEmptyName;
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
+ /* HACK: because of a problem with rpcrt4, rpcserver is hacked to return 6 for ERROR_SERVICE_DOES_NOT_EXIST */
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
return FALSE;
}
+ /*
+ * NOTE: A size of 1 character would be enough, but tests show that
+ * Windows returns 2 characters instead, certainly due to a WCHAR/bytes
+ * mismatch in their code.
+ */
if (!lpServiceName || *lpcchBuffer < sizeof(WCHAR))
{
lpNameBuffer = szEmptyName;
}
+/**********************************************************************
+ * I_ScValidatePnpService
+ *
+ * Undocumented
+ *
+ * @implemented
+ */
+DWORD
+WINAPI
+I_ScValidatePnpService(
+ _In_ LPCWSTR pszMachineName,
+ _In_ LPCWSTR pszServiceName,
+ _Out_ SERVICE_STATUS_HANDLE *phServiceStatus)
+{
+ SC_RPC_HANDLE hSCManager = NULL;
+ SERVICE_STATUS_HANDLE hServiceStatus = NULL;
+ DWORD dwError;
+
+ TRACE("I_ScValidatePnpService(%S %S %p)\n",
+ pszMachineName, pszServiceName, phServiceStatus);
+
+ hSCManager = OpenSCManagerW(pszMachineName,
+ SERVICES_ACTIVE_DATABASEW,
+ SC_MANAGER_CONNECT);
+ if (hSCManager == NULL)
+ {
+ dwError = GetLastError();
+ goto done;
+ }
+
+ RpcTryExcept
+ {
+ dwError = RI_ScValidatePnPService(hSCManager,
+ (LPWSTR)pszServiceName,
+ (RPC_SERVICE_STATUS_HANDLE *)&hServiceStatus);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwError = ScmRpcStatusToWinError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ *phServiceStatus = hServiceStatus;
+
+done:
+ if (hSCManager != NULL)
+ CloseServiceHandle(hSCManager);
+
+ return dwError;
+}
+
+
/**********************************************************************
* LockServiceDatabase
*
hEvent = OpenEventW(SYNCHRONIZE, FALSE, SCM_START_EVENT);
if (hEvent == NULL)
{
- if (GetLastError() != ERROR_FILE_NOT_FOUND) return;
+ if (GetLastError() != ERROR_FILE_NOT_FOUND)
+ return;
/* Try to create a new event */
hEvent = CreateEventW(NULL, TRUE, FALSE, SCM_START_EVENT);
- if (hEvent == NULL) return;
+ if (hEvent == NULL)
+ return;
}
/* Wait for 3 minutes */
}
RpcEndExcept;
+ SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
TRACE("ROpenSCManagerA() failed (Error %lu)\n", dwError);
- SetLastError(dwError);
return NULL;
}
}
RpcEndExcept;
+ SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
TRACE("ROpenSCManagerW() failed (Error %lu)\n", dwError);
- SetLastError(dwError);
return NULL;
}
return TRUE;
}
+DWORD
+I_ScQueryServiceTagInfo(PVOID Unused,
+ TAG_INFO_LEVEL dwInfoLevel,
+ PTAG_INFO_NAME_FROM_TAG InOutParams)
+{
+ SC_HANDLE hScm;
+ DWORD dwError;
+ PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams;
+ PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutParams;
+ LPWSTR lpszName;
+
+ /* We only support one class */
+ if (dwInfoLevel != TagInfoLevelNameFromTag)
+ {
+ return ERROR_RETRY;
+ }
+
+ /* Validate input structure */
+ if (InOutParams->InParams.dwPid == 0 || InOutParams->InParams.dwTag == 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Validate output structure */
+ if (InOutParams->OutParams.pszName != NULL)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Open service manager */
+ hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
+ if (hScm == NULL)
+ {
+ return GetLastError();
+ }
+
+ /* Setup call parameters */
+ InParams = &InOutParams->InParams;
+ OutParams = NULL;
+
+ /* Call SCM to query tag information */
+ RpcTryExcept
+ {
+ dwError = RI_ScQueryServiceTagInfo(hScm, TagInfoLevelNameFromTag, &InParams, &OutParams);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwError = ScmRpcStatusToWinError(RpcExceptionCode());
+ }
+ RpcEndExcept;
+
+ /* Quit if not a success */
+ if (dwError != ERROR_SUCCESS)
+ {
+ goto Cleanup;
+ }
+
+ /* OutParams must be set now and we must have a name */
+ if (OutParams == NULL ||
+ OutParams->pszName == NULL)
+ {
+ dwError = ERROR_INVALID_DATA;
+ goto Cleanup;
+ }
+
+ /* Copy back what SCM returned */
+ lpszName = LocalAlloc(LPTR,
+ sizeof(WCHAR) * wcslen(OutParams->pszName) + sizeof(UNICODE_NULL));
+ if (lpszName == NULL)
+ {
+ dwError = GetLastError();
+ goto Cleanup;
+ }
+
+ wcscpy(lpszName, OutParams->pszName);
+ InOutParams->OutParams.pszName = lpszName;
+ InOutParams->OutParams.TagType = OutParams->TagType;
+
+Cleanup:
+ CloseServiceHandle(hScm);
+
+ /* Free memory allocated by SCM */
+ if (OutParams != NULL)
+ {
+ if (OutParams->pszName != NULL)
+ {
+ midl_user_free(OutParams->pszName);
+ }
+
+ midl_user_free(OutParams);
+ }
+
+ return dwError;
+}
+
+/**********************************************************************
+ * I_QueryTagInformation
+ *
+ * @implemented
+ */
+DWORD WINAPI
+I_QueryTagInformation(PVOID Unused,
+ TAG_INFO_LEVEL dwInfoLevel,
+ PTAG_INFO_NAME_FROM_TAG InOutParams)
+{
+ /*
+ * We only support one information class and it
+ * needs parameters
+ */
+ if (dwInfoLevel != TagInfoLevelNameFromTag ||
+ InOutParams == NULL)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Validate input structure */
+ if (InOutParams->InParams.dwPid == 0 || InOutParams->InParams.dwTag == 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Validate output structure */
+ if (InOutParams->OutParams.pszName != NULL)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Call internal function for the RPC call */
+ return I_ScQueryServiceTagInfo(Unused, TagInfoLevelNameFromTag, InOutParams);
+}
+
/* EOF */