From: Michael Müller michael@fds-team.de
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ntdll/actctx.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 157 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 956f2559eb..3ba407d83a 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -490,17 +490,19 @@ enum assembly_type
struct assembly { - enum assembly_type type; - struct assembly_identity id; - struct file_info manifest; - WCHAR *directory; - BOOL no_inherit; - struct dll_redirect *dlls; - unsigned int num_dlls; - unsigned int allocated_dlls; - struct entity_array entities; - COMPATIBILITY_CONTEXT_ELEMENT* compat_contexts; - ULONG num_compat_contexts; + enum assembly_type type; + struct assembly_identity id; + struct file_info manifest; + WCHAR *directory; + BOOL no_inherit; + struct dll_redirect *dlls; + unsigned int num_dlls; + unsigned int allocated_dlls; + struct entity_array entities; + COMPATIBILITY_CONTEXT_ELEMENT *compat_contexts; + ULONG num_compat_contexts; + ACTCTX_REQUESTED_RUN_LEVEL run_level; + ULONG ui_access; };
enum context_sections @@ -629,6 +631,10 @@ static const WCHAR compatibilityNSW[] = {'u','r','n',':','s','c','h','e','m','a' static const WCHAR applicationW[] = {'a','p','p','l','i','c','a','t','i','o','n',0}; static const WCHAR supportedOSW[] = {'s','u','p','p','o','r','t','e','d','O','S',0}; static const WCHAR IdW[] = {'I','d',0}; +static const WCHAR requestedExecutionLevelW[] = {'r','e','q','u','e','s','t','e','d','E','x','e','c','u','t','i','o','n','L','e','v','e','l',0}; +static const WCHAR requestedPrivilegesW[] = {'r','e','q','u','e','s','t','e','d','P','r','i','v','i','l','e','g','e','s',0}; +static const WCHAR securityW[] = {'s','e','c','u','r','i','t','y',0}; +static const WCHAR trustInfoW[] = {'t','r','u','s','t','I','n','f','o',0};
struct olemisc_entry { @@ -2317,6 +2323,141 @@ static BOOL parse_compatibility_elem(xmlbuf_t* xmlbuf, struct assembly* assembly return ret; }
+static BOOL parse_requested_execution_level_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl) +{ + static const WCHAR levelW[] = {'l','e','v','e','l',0}; + static const WCHAR asInvokerW[] = {'a','s','I','n','v','o','k','e','r',0}; + static const WCHAR requireAdministratorW[] = {'r','e','q','u','i','r','e','A','d','m','i','n','i','s','t','r','a','t','o','r',0}; + static const WCHAR highestAvailableW[] = {'h','i','g','h','e','s','t','A','v','a','i','l','a','b','l','e',0}; + static const WCHAR uiAccessW[] = {'u','i','A','c','c','e','s','s',0}; + static const WCHAR falseW[] = {'f','a','l','s','e',0}; + static const WCHAR trueW[] = {'t','r','u','e',0}; + + xmlstr_t attr_name, attr_value, elem; + BOOL end = FALSE, ret = TRUE, error; + + /* Multiple requestedExecutionLevel elements are not supported. */ + if (assembly->run_level != ACTCTX_RUN_LEVEL_UNSPECIFIED) + return FALSE; + + while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end)) + { + if (xmlstr_cmp(&attr_name, levelW)) + { + if (xmlstr_cmpi(&attr_value, asInvokerW)) + assembly->run_level = ACTCTX_RUN_LEVEL_AS_INVOKER; + else if (xmlstr_cmpi(&attr_value, highestAvailableW)) + assembly->run_level = ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE; + else if (xmlstr_cmpi(&attr_value, requireAdministratorW)) + assembly->run_level = ACTCTX_RUN_LEVEL_REQUIRE_ADMIN; + else + FIXME("unknown execution level: %s\n", debugstr_xmlstr(&attr_value)); + } + else if (xmlstr_cmp(&attr_name, uiAccessW)) + { + if (xmlstr_cmpi(&attr_value, falseW)) + assembly->ui_access = FALSE; + else if (xmlstr_cmpi(&attr_value, trueW)) + assembly->ui_access = TRUE; + else + FIXME("unknown uiAccess value: %s\n", debugstr_xmlstr(&attr_value)); + } + else + FIXME("unknown attr %s=%s\n", debugstr_xmlstr(&attr_name), debugstr_xmlstr(&attr_value)); + } + + if (error) return FALSE; + if (end) return TRUE; + + while (ret && (ret = next_xml_elem(xmlbuf, &elem))) + { + if (xmlstr_cmp_end(&elem, requestedExecutionLevelW)) + { + ret = parse_end_element(xmlbuf); + break; + } + else + { + FIXME("unknown element %s\n", debugstr_xmlstr(&elem)); + ret = parse_unknown_elem(xmlbuf, &elem); + } + } + + return ret; +} + +static BOOL parse_requested_privileges_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl) +{ + xmlstr_t elem; + BOOL ret = TRUE; + + while (ret && (ret = next_xml_elem(xmlbuf, &elem))) + { + if (xmlstr_cmp_end(&elem, requestedPrivilegesW)) + { + ret = parse_end_element(xmlbuf); + break; + } + else if (xmlstr_cmp(&elem, requestedExecutionLevelW)) + ret = parse_requested_execution_level_elem(xmlbuf, assembly, acl); + else + { + WARN("unknown elem %s\n", debugstr_xmlstr(&elem)); + ret = parse_unknown_elem(xmlbuf, &elem); + } + } + + return ret; +} + +static BOOL parse_security_elem(xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl) +{ + xmlstr_t elem; + BOOL ret = TRUE; + + while (ret && (ret = next_xml_elem(xmlbuf, &elem))) + { + if (xmlstr_cmp_end(&elem, securityW)) + { + ret = parse_end_element(xmlbuf); + break; + } + else if (xmlstr_cmp(&elem, requestedPrivilegesW)) + ret = parse_requested_privileges_elem(xmlbuf, assembly, acl); + else + { + WARN("unknown elem %s\n", debugstr_xmlstr(&elem)); + ret = parse_unknown_elem(xmlbuf, &elem); + } + } + + return ret; +} + +static BOOL parse_trust_info_elem(xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl) +{ + xmlstr_t elem; + BOOL ret = TRUE; + + while (ret && (ret = next_xml_elem(xmlbuf, &elem))) + { + if (xmlstr_cmp_end(&elem, trustInfoW)) + { + ret = parse_end_element(xmlbuf); + break; + } + else if (xmlstr_cmp(&elem, securityW)) + ret = parse_security_elem(xmlbuf, assembly, acl); + else + { + WARN("unknown elem %s\n", debugstr_xmlstr(&elem)); + ret = parse_unknown_elem(xmlbuf, &elem); + } + } + + return ret; +} + static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl, struct assembly* assembly, struct assembly_identity* expected_ai) @@ -2405,6 +2546,11 @@ static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl, { ret = parse_clr_surrogate_elem(xmlbuf, assembly, acl); } + else if (xml_elem_cmp(&elem, trustInfoW, asmv2W) || + xml_elem_cmp(&elem, trustInfoW, asmv1W)) + { + ret = parse_trust_info_elem(xmlbuf, assembly, acl); + } else if (xml_elem_cmp(&elem, assemblyIdentityW, asmv1W)) { if (!parse_assembly_identity_elem(xmlbuf, acl->actctx, &assembly->id)) return FALSE;
From: Michael Müller michael@fds-team.de
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
Minor modifications from original to make tests pass on XP, where such context info is not supported.
dlls/kernel32/tests/actctx.c | 243 ++++++++++++++++++++++++++++++++++++++++--- dlls/ntdll/actctx.c | 21 ++++ 2 files changed, 249 insertions(+), 15 deletions(-)
diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index a182cfa4be..cef11a5e63 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -244,6 +244,61 @@ static const char manifest5[] = "</dependency>" "</assembly>";
+static const char manifest6[] = +"<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">" +"<assemblyIdentity version="1.0.0.0" name="Wine.Test" type="win32"></assemblyIdentity>" +"<trustInfo xmlns="urn:schemas-microsoft-com:asm.v1">" +" <security>" +" <requestedPrivileges>" +" <requestedExecutionLevel level="ASINVOKER" uiAccess="false"/>" +" </requestedPrivileges>" +" </security>" +"</trustInfo>" +"</assembly>"; + +static const char manifest7[] = +"<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">" +"<assemblyIdentity version="1.0.0.0" name="Wine.Test" type="win32"></assemblyIdentity>" +"<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">" +" <security>" +" <requestedPrivileges>" +" <requestedExecutionLevel level="requireAdministrator" uiAccess="TRUE"/>" +" </requestedPrivileges>" +" </security>" +"</trustInfo>" +"</assembly>"; + +static const char manifest8[] = +"<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">" +"<assemblyIdentity version="1.0.0.0" name="Wine.Test" type="win32"></assemblyIdentity>" +"<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">" +" <security>" +" <requestedPrivileges>" +" <requestedExecutionLevel level="requireAdministrator" uiAccess="true">" +" </requestedExecutionLevel>" +" </requestedPrivileges>" +" </security>" +"</trustInfo>" +"</assembly>"; + +static const char manifest9[] = +"<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">" +"<assemblyIdentity version="1.0.0.0" name="Wine.Test" type="win32"></assemblyIdentity>" +"<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">" +" <security>" +" <requestedPrivileges>" +" <requestedExecutionLevel level="requireAdministrator"/>" +" </requestedPrivileges>" +" </security>" +"</trustInfo>" +"<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">" +" <security>" +" <requestedPrivileges>" +" </requestedPrivileges>" +" </security>" +"</trustInfo>" +"</assembly>"; + static const char testdep_manifest1[] = "<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">" "<assemblyIdentity type="win32" name="testdep" version="6.5.4.3" processorArchitecture="" ARCH ""/>" @@ -310,6 +365,38 @@ static const char wrong_manifest8[] = "<file></file>" "</assembly>";
+static const char wrong_manifest9[] = +"<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">" +"<assemblyIdentity version="1.0.0.0" name="Wine.Test" type="win32"></assemblyIdentity>" +"<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">" +" <security>" +" <requestedPrivileges>" +" <requestedExecutionLevel level="requireAdministrator"/>" +" <requestedExecutionLevel uiAccess="true"/>" +" </requestedPrivileges>" +" </security>" +"</trustInfo>" +"</assembly>"; + +static const char wrong_manifest10[] = +"<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">" +"<assemblyIdentity version="1.0.0.0" name="Wine.Test" type="win32"></assemblyIdentity>" +"<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">" +" <security>" +" <requestedPrivileges>" +" <requestedExecutionLevel level="requireAdministrator"/>" +" </requestedPrivileges>" +" </security>" +"</trustInfo>" +"<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">" +" <security>" +" <requestedPrivileges>" +" <requestedExecutionLevel uiAccess="true"/>" +" </requestedPrivileges>" +" </security>" +"</trustInfo>" +"</assembly>"; + static const char wrong_depmanifest1[] = "<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">" "<assemblyIdentity type="win32" name="testdep" version="6.5.4.4" processorArchitecture="" ARCH "" />" @@ -783,6 +870,57 @@ static void test_file_info(HANDLE handle, ULONG assid, ULONG fileid, LPCWSTR fil HeapFree(GetProcessHeap(), 0, info); }
+typedef struct { + ACTCTX_REQUESTED_RUN_LEVEL run_level; + DWORD ui_access; +} runlevel_info_t; + +static const runlevel_info_t runlevel_info0 = { + ACTCTX_RUN_LEVEL_UNSPECIFIED, FALSE, +}; + +static const runlevel_info_t runlevel_info6 = { + ACTCTX_RUN_LEVEL_AS_INVOKER, FALSE, +}; + +static const runlevel_info_t runlevel_info7 = { + ACTCTX_RUN_LEVEL_REQUIRE_ADMIN, TRUE, +}; + +static const runlevel_info_t runlevel_info8 = { + ACTCTX_RUN_LEVEL_REQUIRE_ADMIN, TRUE, +}; + +static const runlevel_info_t runlevel_info9 = { + ACTCTX_RUN_LEVEL_REQUIRE_ADMIN, FALSE, +}; + +static void test_runlevel_info(HANDLE handle, const runlevel_info_t *exinfo, int line) +{ + ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION runlevel_info; + SIZE_T size, retsize; + BOOL b; + + size = sizeof(runlevel_info); + b = pQueryActCtxW(0, handle, NULL, + RunlevelInformationInActivationContext, &runlevel_info, + sizeof(runlevel_info), &retsize); + if (!b && GetLastError() == ERROR_INVALID_PARAMETER) + { + win_skip("RunlevelInformationInActivationContext not supported.\n"); + return; + } + + ok_(__FILE__, line)(b, "QueryActCtx failed: %u\n", GetLastError()); + ok_(__FILE__, line)(retsize == size, "size=%ld, expected %ld\n", retsize, size); + + ok_(__FILE__, line)(runlevel_info.ulFlags == 0, "runlevel_info.ulFlags=%x\n", runlevel_info.ulFlags); + ok_(__FILE__, line)(runlevel_info.RunLevel == exinfo->run_level, + "runlevel_info.RunLevel=%u, expected %u\n", runlevel_info.RunLevel, exinfo->run_level); + ok_(__FILE__, line)(runlevel_info.UiAccess == exinfo->ui_access, + "runlevel_info.UiAccess=%u, expected %u\n", runlevel_info.UiAccess, exinfo->ui_access); +} + static HANDLE test_create(const char *file) { ACTCTXW actctx; @@ -814,7 +952,7 @@ static HANDLE test_create(const char *file) return handle; }
-static void test_create_and_fail(const char *manifest, const char *depmanifest, int todo) +static void test_create_and_fail(const char *manifest, const char *depmanifest, int todo, BOOL is_broken) { ACTCTXW actctx; HANDLE handle; @@ -829,8 +967,14 @@ static void test_create_and_fail(const char *manifest, const char *depmanifest, handle = pCreateActCtxW(&actctx); todo_wine_if(todo) { - ok(handle == INVALID_HANDLE_VALUE, "handle != INVALID_HANDLE_VALUE\n"); - ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "GetLastError == %u\n", GetLastError()); + if (is_broken) + ok(broken(handle != INVALID_HANDLE_VALUE) || handle == INVALID_HANDLE_VALUE, + "Unexpected context handle %p.\n", handle); + else + ok(handle == INVALID_HANDLE_VALUE, "Unexpected context handle %p.\n", handle); + + if (handle == INVALID_HANDLE_VALUE) + ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "Unexpected error %d.\n", GetLastError()); } if (handle != INVALID_HANDLE_VALUE) pReleaseActCtx( handle ); DeleteFileA("bad.manifest"); @@ -873,27 +1017,31 @@ static void test_create_fail(void) ok(GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError == %u\n", GetLastError());
trace("wrong_manifest1\n"); - test_create_and_fail(wrong_manifest1, NULL, 0 ); + test_create_and_fail(wrong_manifest1, NULL, 0, FALSE); trace("wrong_manifest2\n"); - test_create_and_fail(wrong_manifest2, NULL, 0 ); + test_create_and_fail(wrong_manifest2, NULL, 0, FALSE); trace("wrong_manifest3\n"); - test_create_and_fail(wrong_manifest3, NULL, 1 ); + test_create_and_fail(wrong_manifest3, NULL, 1, FALSE); trace("wrong_manifest4\n"); - test_create_and_fail(wrong_manifest4, NULL, 1 ); + test_create_and_fail(wrong_manifest4, NULL, 1, FALSE); trace("wrong_manifest5\n"); - test_create_and_fail(wrong_manifest5, NULL, 0 ); + test_create_and_fail(wrong_manifest5, NULL, 0, FALSE); trace("wrong_manifest6\n"); - test_create_and_fail(wrong_manifest6, NULL, 0 ); + test_create_and_fail(wrong_manifest6, NULL, 0, FALSE); trace("wrong_manifest7\n"); - test_create_and_fail(wrong_manifest7, NULL, 1 ); + test_create_and_fail(wrong_manifest7, NULL, 1, FALSE); trace("wrong_manifest8\n"); - test_create_and_fail(wrong_manifest8, NULL, 0 ); + test_create_and_fail(wrong_manifest8, NULL, 0, FALSE); + trace("wrong_manifest9\n"); + test_create_and_fail(wrong_manifest9, NULL, 0, TRUE /* WinXP */); + trace("wrong_manifest10\n"); + test_create_and_fail(wrong_manifest10, NULL, 0, TRUE /* WinXP */); trace("UTF-16 manifest1 without BOM\n"); test_create_wide_and_fail(manifest1, FALSE ); trace("manifest2\n"); - test_create_and_fail(manifest2, NULL, 0 ); + test_create_and_fail(manifest2, NULL, 0, FALSE); trace("manifest2+depmanifest1\n"); - test_create_and_fail(manifest2, wrong_depmanifest1, 0 ); + test_create_and_fail(manifest2, wrong_depmanifest1, 0, FALSE); }
struct strsection_header @@ -1825,8 +1973,6 @@ static void test_actctx(void) HANDLE handle; BOOL b;
- test_create_fail(); - trace("default actctx\n");
b = pGetCurrentActCtx(&handle); @@ -1835,6 +1981,7 @@ static void test_actctx(void) if(b) { test_basic_info(handle, __LINE__); test_detailed_info(handle, &detailed_info0, __LINE__); + test_runlevel_info(handle, &runlevel_info0, __LINE__); pReleaseActCtx(handle); }
@@ -2006,6 +2153,71 @@ static void test_actctx(void) pReleaseActCtx(handle); }
+ trace("manifest6\n"); + + if(create_manifest_file("test6.manifest", manifest6, -1, NULL, NULL)) { + handle = test_create("test6.manifest"); + ok(handle != INVALID_HANDLE_VALUE || broken(handle == INVALID_HANDLE_VALUE) /* WinXP */, + "Unexpected context handle %p.\n", handle); + DeleteFileA("test6.manifest"); + DeleteFileA("testdep.manifest"); + if(handle != INVALID_HANDLE_VALUE) + { + test_runlevel_info(handle, &runlevel_info6, __LINE__); + pReleaseActCtx(handle); + } + } + else + skip("Could not create manifest file 6\n"); + + trace("manifest7\n"); + + if(create_manifest_file("test7.manifest", manifest7, -1, NULL, NULL)) { + handle = test_create("test7.manifest"); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + DeleteFileA("test7.manifest"); + DeleteFileA("testdep.manifest"); + if(handle != INVALID_HANDLE_VALUE) + { + test_runlevel_info(handle, &runlevel_info7, __LINE__); + pReleaseActCtx(handle); + } + } + else + skip("Could not create manifest file 7\n"); + + trace("manifest8\n"); + + if(create_manifest_file("test8.manifest", manifest8, -1, NULL, NULL)) { + handle = test_create("test8.manifest"); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + DeleteFileA("test8.manifest"); + DeleteFileA("testdep.manifest"); + if(handle != INVALID_HANDLE_VALUE) + { + test_runlevel_info(handle, &runlevel_info8, __LINE__); + pReleaseActCtx(handle); + } + } + else + skip("Could not create manifest file 8\n"); + + trace("manifest9\n"); + + if(create_manifest_file("test9.manifest", manifest9, -1, NULL, NULL)) { + handle = test_create("test9.manifest"); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + DeleteFileA("test9.manifest"); + DeleteFileA("testdep.manifest"); + if(handle != INVALID_HANDLE_VALUE) + { + test_runlevel_info(handle, &runlevel_info9, __LINE__); + pReleaseActCtx(handle); + } + } + else + skip("Could not create manifest file 9\n"); + trace("manifest4\n");
if(!create_manifest_file("test4.manifest", manifest4, -1, NULL, NULL)) { @@ -2731,6 +2943,7 @@ START_TEST(actctx) }
test_actctx(); + test_create_fail(); test_CreateActCtx(); test_findsectionstring(); test_ZombifyActCtx(); diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 3ba407d83a..4a3370048f 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -5271,6 +5271,27 @@ NTSTATUS WINAPI RtlQueryInformationActivationContext( ULONG flags, HANDLE handle } break;
+ case RunlevelInformationInActivationContext: + { + ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION *acrli = buffer; + struct assembly *assembly; + SIZE_T len; + + if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER; + + len = sizeof(*acrli); + if (retlen) *retlen = len; + if (!buffer || bufsize < len) + return STATUS_BUFFER_TOO_SMALL; + + assembly = actctx->assemblies; + + acrli->ulFlags = 0; + acrli->RunLevel = assembly ? assembly->run_level : ACTCTX_RUN_LEVEL_UNSPECIFIED; + acrli->UiAccess = assembly ? assembly->ui_access : 0; + } + break; + default: FIXME( "class %u not implemented\n", class ); return STATUS_NOT_IMPLEMENTED;