Tests for read-operations has been done.
http://newtestbot.winehq.org/JobDetails.pl?Key=942
All the results are expected:
1. query_value prefer values in hkcu.
2. query_key_info gives the count of subkeys and values distincted.
3. enum_value & enum_key combine result from hkcu & hklm and return in
sorted order
I've looked into server/registry.c to find the subkeys are stored in
alphabet order and is located by binary search. So when enumerating
subkeys or values from hkcr, the two branches hkcu and hklm can be
combined using a algorithm like part of merge_sort.

Had hard time testing what happens using a dumped key handle of hkcr
from another user, as mentioned in last mail. Steps in my test:
1. make sure hkcu/software/classes/subkey1 exist in hkcu of both user1
and user2.
2. program1 of user1 set 'val1' in hkcu/software/classes/subkey1 to 'user1'
3. program1 opens a handle to hkcr/subkey1, print it out then wait but not exit.
3. program2 of user2 dumps the handle from program1 to program2, set
value 'val1' to 'user2' with that handle.
4. program1 continues, open hkcu/classes/subkey1. query and print out
current value of 'val1'.
Here we care what value is eventually set to 'val1' in user1. As we
know a handle is associated with a kernel object. dumped handle points
to same object as original.
- If the final value is 'user1', that denotes operations by user2 with
hckr key objects created from user1 have no effect on user1.
- If the value is 'user2', operations from another user changes
content from owner user, obviously the key-view is associated with the
own user I'm considering to add a field 'owner' in my key view object.
The test code is attached, and output is as following, note that the
second program start running when the first paused.

>runas /user:user1 "testcls 1"
program1 on user1 has pid : 2092
'val1' set to 'user1' on user1
handle of subkey1 opened from hkcr : 000007D2
come back after runing program2 as user2
press any key to continue . .
'val1' on user1 is 'user2' now

>runas /user:user2 "testcls 2"
input pid of program1
2092
input handle of subkey1 in program1
7d2
dumped handle on user2 : 000007B0
'val1' set to 'user2'

The final result turned out to be 'user2'. As expected, isn't it?

Till now, most of my test work has finished. I'm going to make out a
stage conclusion soon then I'll come to the main point - the implement
of merging.
#include "stdio.h"
#include "stdlib.h"
#include "windows.h"

int main1()
{
    DWORD res, size, type;
    HKEY hkey;
    char name[32];

    printf("program1 on user1 has pid : %d\n", GetCurrentProcessId());

    /* create subkey1 in hkcu */
    if ((res = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\subkey1", 0, NULL, 0,
                                KEY_SET_VALUE|KEY_QUERY_VALUE,
                                NULL, &hkey, NULL )) != ERROR_SUCCESS)
    {
        printf("RegCreateKeyExA failed with %08X\n", res);
        return -1;
    }

    /* set val1 to user1 */
    strcpy(name, "user1");
    if ((res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (CONST BYTE*)name, strlen(name))) != ERROR_SUCCESS)
    {
        printf("RegSetValueExA failed with %08X\n", res);
        return -1;
    }
    if ((res = RegFlushKey(hkey)) != ERROR_SUCCESS)
    {
        printf("RegFlushKey failed with %08X\n", res);
        return -1;
    }
    printf("'val1' set to '%s' on user1\n", name);
    RegCloseKey(hkey);
    
    /* open subkey1 from hkcr */
    if ((res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "subkey1", 0,
                              KEY_SET_VALUE|KEY_QUERY_VALUE,
                              &hkey )) != ERROR_SUCCESS)
    {
        printf("RegOpenKeyExA failed with %08X\n", res);
        return -1;
    }
    printf("handle of subkey1 opened from hkcr : %p\n", hkey);

    /* wait program2 to dump the handle */
    printf("come back after runing program2 as user2\n");
    system("pause");
    RegCloseKey(hkey);
    
    /* see what is in val1 now */
    if ((res = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\subkey1", 0,
                              KEY_SET_VALUE|KEY_QUERY_VALUE,
                              &hkey )) != ERROR_SUCCESS)
    {
        printf("RegOpenKeyExA failed with %08X\n", res);
        return -1;
    }
    type = REG_SZ;
    size = sizeof(name);
    if ((res = RegQueryValueExA(hkey, "val1", 0, &type, (BYTE*)name, &size)) != ERROR_SUCCESS)
    {
        printf("RegQueryValueExA failed with %08X\n", res);
        return -1;
    }
    printf("'val1' on user1 is '%s' now\n", name);
    RegCloseKey(hkey);
    return 0;
}

int main2()
{
    DWORD pid1, res, size, type;
    HKEY hkey;
    HANDLE hprocess, htoken;
    TOKEN_PRIVILEGES tkp;
    char name[32];

    /* get a debug privilege so that we can open process of another user */
    if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &htoken))
    {
        printf("OpenProcessToken failed with 0x%08X\n", GetLastError());
        return -1;
    }
    tkp.PrivilegeCount = 1;
    LookupPrivilegeValue(NULL,SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if(!AdjustTokenPrivileges(htoken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
    {
        printf("AdjustTokenPrivileges failed with 0x%08X\n", GetLastError());
        return -1;
    }
    CloseHandle(htoken);

    /* dump handle from program1 */
    printf("input pid of program1\n");
    scanf("%d", &pid1);
    hprocess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid1);
    if (!hprocess)
    {
        printf("OpenProcess failed with 0x%08X\n", GetLastError());
        return -1;
    }
    printf("input handle of subkey1 in program1\n");
    scanf("%x", &hkey);
    if (!DuplicateHandle(hprocess, hkey, GetCurrentProcess(), (LPHANDLE)&hkey, KEY_SET_VALUE|KEY_QUERY_VALUE, FALSE, NULL))
    {
        printf("DuplicateHandle failed with 0x%08X\n", GetLastError());
        return -1;
    }
    printf("dumped handle on user2 : %p\n", hkey);

    /* set val1 to user2 using the dumped handle */;
    strcpy(name, "user2");
    if ((res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (CONST BYTE*)name, strlen(name))) != ERROR_SUCCESS)
    {
        printf("RegSetValueExA failed with %08X\n", res);
        return -1;
    }
    if ((res = RegFlushKey(hkey)) != ERROR_SUCCESS)
    {
        printf("RegFlushKey failed with %08X\n", res);
        return -1;
    }
    printf("'val1' set to '%s'\n", name);

    CloseHandle(hprocess);
    RegCloseKey(hkey);
    return 0;
}

int main(int argc, char **argv)
{
    if (argc == 2)
    {
        if (*argv[1] == '1')
            return main1();
        else if (*argv[1] == '2')
            return main2();
    }
    printf("give 1 or 2 as parameter, and run with different user please\n");
    return 1;
}


Reply via email to