Author: fireball
Date: Mon Jan 14 14:46:14 2008
New Revision: 31768
URL:
http://svn.reactos.org/svn/reactos?rev=31768&view=rev
Log:
- Implement canonicalizing the service binary path properly, handling all possible cases
(instead of a memory-overwriting hack Christoph noticed yesterday).
Modified:
trunk/reactos/base/system/services/rpcserver.c
Modified: trunk/reactos/base/system/services/rpcserver.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/rpcse…
==============================================================================
--- trunk/reactos/base/system/services/rpcserver.c (original)
+++ trunk/reactos/base/system/services/rpcserver.c Mon Jan 14 14:46:14 2008
@@ -993,6 +993,380 @@
DPRINT("ScmrChangeServiceConfigW() done (Error %lu)\n", dwError);
return dwError;
+}
+
+/* Create a path suitable for the bootloader out of the full path */
+DWORD
+ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
+{
+ DWORD ServiceNameLen, BufferSize, ExpandedLen;
+ WCHAR Dest;
+ WCHAR *Expanded;
+ UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE SymbolicLinkHandle;
+
+ DPRINT("ScmConvertToBootPathName %S\n", CanonName);
+
+ ServiceNameLen = wcslen(CanonName);
+ /* First check, if it's already good */
+ if (ServiceNameLen > 12 &&
+ !wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
+ {
+ *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) +
sizeof(WCHAR));
+
+ if (*RelativeName == NULL)
+ {
+ DPRINT1("Error allocating memory for boot driver name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Copy it */
+ wcscpy(*RelativeName, CanonName);
+
+ DPRINT1("Bootdriver name %S\n", *RelativeName);
+ return ERROR_SUCCESS;
+ }
+
+ /* If it has %SystemRoot% prefix, substitute it to \System*/
+ if (ServiceNameLen > 13 &&
+ !wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
+ {
+ /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
+ *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
+
+ if (*RelativeName == NULL)
+ {
+ DPRINT1("Error allocating memory for boot driver name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Copy it */
+ wcscpy(*RelativeName, L"\\SystemRoot\\");
+ wcscat(*RelativeName, CanonName + 13);
+
+ DPRINT1("Bootdriver name %S\n", *RelativeName);
+ return ERROR_SUCCESS;
+ }
+
+ /* Get buffer size needed for expanding env strings */
+ BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
+
+ if (BufferSize <= 1)
+ {
+ DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
+ return ERROR_INVALID_ENVIRONMENT;
+ }
+
+ /* Allocate memory, since the size is known now */
+ Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
+ if (!Expanded)
+ {
+ DPRINT1("Error allocating memory for boot driver name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Expand it */
+ if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize)
>
+ BufferSize)
+ {
+ DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
+ LocalFree(Expanded);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Convert to NY-style path */
+ if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
+ {
+ DPRINT1("Error during a call to RtlDosPathNameToNtPathName_U()\n");
+ return ERROR_INVALID_ENVIRONMENT;
+ }
+
+ DPRINT("Converted to NT-style %wZ\n", &NtPathName);
+
+ /* No need to keep the dos-path anymore */
+ LocalFree(Expanded);
+
+ /* Copy it to the allocated place */
+ Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
+ if (!Expanded)
+ {
+ DPRINT1("Error allocating memory for boot driver name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ ExpandedLen = NtPathName.Length / sizeof(WCHAR);
+ wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
+ Expanded[ExpandedLen] = 0;
+
+ if (ServiceNameLen > ExpandedLen &&
+ !wcsnicmp(Expanded, CanonName, ExpandedLen))
+ {
+ /* Only \SystemRoot\ is missing */
+ *RelativeName = LocalAlloc(LMEM_ZEROINIT,
+ (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
+
+ if (*RelativeName == NULL)
+ {
+ DPRINT1("Error allocating memory for boot driver name!\n");
+ LocalFree(Expanded);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ wcscpy(*RelativeName, L"\\SystemRoot\\");
+ wcscat(*RelativeName, CanonName + ExpandedLen);
+
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_SUCCESS;
+ }
+
+ /* The most complex case starts here */
+ RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SystemRoot,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ /* Open this symlink */
+ Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY,
&ObjectAttributes);
+
+ if (NT_SUCCESS(Status))
+ {
+ LinkTarget.Length = 0;
+ LinkTarget.MaximumLength = 0;
+
+ DPRINT("Opened symbolic link object\n");
+
+ Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget,
&BufferSize);
+ if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* Check if required buffer size is sane */
+ if (BufferSize > 0xFFFD)
+ {
+ DPRINT1("Too large buffer required\n");
+ *RelativeName = 0;
+
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ LocalFree(Expanded);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Alloc the string */
+ LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
+ if (!LinkTarget.Buffer)
+ {
+ DPRINT1("Unable to alloc buffer\n");
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ LocalFree(Expanded);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Do a real query now */
+ LinkTarget.Length = BufferSize;
+ LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
+
+ Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget,
&BufferSize);
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("LinkTarget: %wZ\n", &LinkTarget);
+
+ ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
+ if ((ServiceNameLen > ExpandedLen) &&
+ !wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
+ {
+ *RelativeName = LocalAlloc(LMEM_ZEROINIT,
+ (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) +
13*sizeof(WCHAR));
+
+ if (*RelativeName == NULL)
+ {
+ DPRINT1("Unable to alloc buffer\n");
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ LocalFree(Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Copy it over, substituting the first part
+ with SystemRoot */
+ wcscpy(*RelativeName, L"\\SystemRoot\\");
+ wcscat(*RelativeName, CanonName+ExpandedLen+1);
+
+ /* Cleanup */
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ LocalFree(Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+
+ /* Return success */
+ return ERROR_SUCCESS;
+ }
+ else
+ {
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ LocalFree(Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ DPRINT1("Error, Status = %08X\n", Status);
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ LocalFree(Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ DPRINT1("Error, Status = %08X\n", Status);
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ LocalFree(Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ DPRINT1("Error, Status = %08X\n", Status);
+ LocalFree(Expanded);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Failure */
+ *RelativeName = NULL;
+ return ERROR_INVALID_PARAMETER;
+}
+
+DWORD
+ScmCanonDriverImagePath(DWORD dwStartType,
+ wchar_t *lpServiceName,
+ wchar_t **lpCanonName)
+{
+ DWORD ServiceNameLen, Result;
+ UNICODE_STRING NtServiceName;
+ WCHAR *RelativeName;
+ WCHAR *SourceName = lpServiceName;
+
+ /* Calculate the length of the service's name */
+ ServiceNameLen = wcslen(lpServiceName);
+
+ /* 12 is wcslen(L"\\SystemRoot\\") */
+ if (ServiceNameLen > 12 &&
+ !wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
+ {
+ /* SystemRoot prefix is already included */
+
+ *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) +
sizeof(WCHAR));
+
+ if (*lpCanonName == NULL)
+ {
+ DPRINT1("Error allocating memory for canonized service name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* If it's a boot-time driver, it must be systemroot relative */
+ if (dwStartType == SERVICE_BOOT_START)
+ SourceName += 12;
+
+ /* Copy it */
+ wcscpy(*lpCanonName, SourceName);
+
+ DPRINT("Canonicalized name %S\n", *lpCanonName);
+ return NO_ERROR;
+ }
+
+ /* Check if it has %SystemRoot% (len=13) */
+ if (ServiceNameLen > 13 &&
+ !wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
+ {
+ /* Substitute %SystemRoot% with \\SystemRoot\\ */
+ *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) +
sizeof(WCHAR));
+
+ if (*lpCanonName == NULL)
+ {
+ DPRINT1("Error allocating memory for canonized service name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* If it's a boot-time driver, it must be systemroot relative */
+ if (dwStartType == SERVICE_BOOT_START)
+ wcscpy(*lpCanonName, L"\\SystemRoot\\");
+
+ wcscat(*lpCanonName, lpServiceName);
+
+ DPRINT("Canonicalized name %S\n", *lpCanonName);
+ return NO_ERROR;
+ }
+
+ /* Check if it's a relative path name */
+ if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
+ {
+ *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) +
sizeof(WCHAR));
+
+ if (*lpCanonName == NULL)
+ {
+ DPRINT1("Error allocating memory for canonized service name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Just copy it over without changing */
+ wcscpy(*lpCanonName, lpServiceName);
+
+ return NO_ERROR;
+ }
+
+ /* It seems to be a DOS path, convert it */
+ if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
+ {
+ DPRINT1("RtlDosPathNameToNtPathName_U() failed!\n");
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
+
+ if (*lpCanonName == NULL)
+ {
+ DPRINT1("Error allocating memory for canonized service name!\n");
+ RtlFreeUnicodeString(&NtServiceName);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Copy the string */
+ wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
+
+ /* The unicode string is not needed anymore */
+ RtlFreeUnicodeString(&NtServiceName);
+
+ if (dwStartType != SERVICE_BOOT_START)
+ {
+ DPRINT("Canonicalized name %S\n", *lpCanonName);
+ return NO_ERROR;
+ }
+
+ /* The service is boot-started, so must be relative */
+ Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
+ if (Result)
+ {
+ /* There is a problem, free name and return */
+ LocalFree(*lpCanonName);
+ DPRINT1("Error converting named!\n");
+ return Result;
+ }
+
+ ASSERT(RelativeName);
+
+ /* Copy that string */
+ wcscpy(*lpCanonName, RelativeName + 12);
+
+ /* Free the allocated buffer */
+ LocalFree(RelativeName);
+
+ DPRINT("Canonicalized name %S\n", *lpCanonName);
+
+ /* Success */
+ return NO_ERROR;
}
@@ -1058,24 +1432,12 @@
if (dwServiceType & SERVICE_DRIVER)
{
- lpImagePath = (WCHAR*) HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- (wcslen(lpBinaryPathName) + 5) * sizeof(WCHAR));
- if (lpImagePath == NULL)
- {
- dwError = ERROR_NOT_ENOUGH_MEMORY;
+ dwError = ScmCanonDriverImagePath(dwStartType,
+ lpBinaryPathName,
+ &lpImagePath);
+
+ if (dwError != ERROR_SUCCESS)
goto done;
- }
-
- if (lpBinaryPathName[1] == L':')
- {
- wcscpy(lpImagePath, L"\\??\\");
- wcscat(lpImagePath, lpBinaryPathName);
- }
- else
- {
- wcscpy(lpImagePath, lpBinaryPathName);
- }
}
/* Allocate a new service entry */