database.c

来自「一个类似windows」· C语言 代码 · 共 928 行 · 第 1/2 页

C
928
字号
            /* FIXME: Add current service to 'failed service' list */
            DPRINT("Service '%S' failed\n", Service->lpServiceName);
            break;
        }

        if (!NT_SUCCESS(Status))
            break;

        DPRINT("Comparing: '%S'  '%wZ'\n", Service->lpServiceName, &DirInfo->ObjectName);

        if (_wcsicmp(Service->lpServiceName, DirInfo->ObjectName.Buffer) == 0)
        {
            DPRINT("Found: '%S'  '%wZ'\n",
                   Service->lpServiceName, &DirInfo->ObjectName);

            /* Mark service as 'running' */
            Service->Status.dwCurrentState = SERVICE_RUNNING;

            /* Mark the service group as 'running' */
            if (Service->lpGroup != NULL)
            {
                Service->lpGroup->ServicesRunning = TRUE;
            }

            break;
        }
    }

    HeapFree(GetProcessHeap(),
             0,
             DirInfo);
    NtClose(DirHandle);

    return STATUS_SUCCESS;
}


VOID
ScmGetBootAndSystemDriverState(VOID)
{
    PLIST_ENTRY ServiceEntry;
    PSERVICE CurrentService;

    DPRINT("ScmGetBootAndSystemDriverState() called\n");

    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

        if (CurrentService->dwStartType == SERVICE_BOOT_START ||
            CurrentService->dwStartType == SERVICE_SYSTEM_START)
        {
            /* Check driver */
            DPRINT("  Checking service: %S\n", CurrentService->lpServiceName);

            ScmCheckDriver(CurrentService);
        }

        ServiceEntry = ServiceEntry->Flink;
    }

    DPRINT("ScmGetBootAndSystemDriverState() done\n");
}


static NTSTATUS
ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
{
    PSCM_START_PACKET StartPacket;
    DWORD TotalLength;
#if 0
    DWORD Length;
#endif
    PWSTR Ptr;
    DWORD Count;

    DPRINT("ScmSendStartCommand() called\n");

    /* Calculate the total length of the start command line */
    TotalLength = wcslen(Service->lpServiceName) + 1;
#if 0
    if (Arguments != NULL)
    {
        Ptr = Arguments;
        while (*Ptr)
        {
            Length = wcslen(Ptr) + 1;
            TotalLength += Length;
            Ptr += Length;
        }
    }
#endif
    TotalLength++;

    /* Allocate start command packet */
    StartPacket = HeapAlloc(GetProcessHeap(),
                            HEAP_ZERO_MEMORY,
                            sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
    if (StartPacket == NULL)
        return STATUS_INSUFFICIENT_RESOURCES;

    StartPacket->Command = SCM_START_COMMAND;
    StartPacket->Size = TotalLength;
    Ptr = &StartPacket->Arguments[0];
    wcscpy(Ptr, Service->lpServiceName);
    Ptr += (wcslen(Service->lpServiceName) + 1);

    /* FIXME: Copy argument list */

    *Ptr = 0;

    /* Send the start command */
    WriteFile(Service->ControlPipeHandle,
              StartPacket,
              sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
              &Count,
              NULL);

    /* FIXME: Read the reply */

    HeapFree(GetProcessHeap(),
             0,
             StartPacket);

    DPRINT("ScmSendStartCommand() done\n");

    return STATUS_SUCCESS;
}


static NTSTATUS
ScmStartUserModeService(PSERVICE Service)
{
    RTL_QUERY_REGISTRY_TABLE QueryTable[3];
    PROCESS_INFORMATION ProcessInformation;
    STARTUPINFOW StartupInfo;
    UNICODE_STRING ImagePath;
    ULONG Type;
    BOOL Result;
    NTSTATUS Status;

    RtlInitUnicodeString(&ImagePath, NULL);

    /* Get service data */
    RtlZeroMemory(&QueryTable,
                  sizeof(QueryTable));

    QueryTable[0].Name = L"Type";
    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
    QueryTable[0].EntryContext = &Type;

    QueryTable[1].Name = L"ImagePath";
    QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
    QueryTable[1].EntryContext = &ImagePath;

    Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
                                    Service->lpServiceName,
                                    QueryTable,
                                    NULL,
                                    NULL);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
        return Status;
    }
    DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
    DPRINT("Type: %lx\n", Type);

    /* Create '\\.\pipe\net\NtControlPipe' instance */
    Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
                                                  PIPE_ACCESS_DUPLEX,
                                                  PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
                                                  100,
                                                  8000,
                                                  4,
                                                  30000,
                                                  NULL);
    DPRINT("CreateNamedPipeW() done\n");
    if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
    {
        DPRINT1("Failed to create control pipe!\n");
        return STATUS_UNSUCCESSFUL;
    }

    StartupInfo.cb = sizeof(StartupInfo);
    StartupInfo.lpReserved = NULL;
    StartupInfo.lpDesktop = NULL;
    StartupInfo.lpTitle = NULL;
    StartupInfo.dwFlags = 0;
    StartupInfo.cbReserved2 = 0;
    StartupInfo.lpReserved2 = 0;

    Result = CreateProcessW(ImagePath.Buffer,
                            NULL,
                            NULL,
                            NULL,
                            FALSE,
                            DETACHED_PROCESS | CREATE_SUSPENDED,
                            NULL,
                            NULL,
                            &StartupInfo,
                            &ProcessInformation);
    RtlFreeUnicodeString(&ImagePath);

    if (!Result)
    {
        /* Close control pipe */
        CloseHandle(Service->ControlPipeHandle);
        Service->ControlPipeHandle = INVALID_HANDLE_VALUE;

        DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
        return STATUS_UNSUCCESSFUL;
    }

    DPRINT("Process Id: %lu  Handle %lx\n",
           ProcessInformation.dwProcessId,
           ProcessInformation.hProcess);
    DPRINT("Thread Id: %lu  Handle %lx\n",
           ProcessInformation.dwThreadId,
           ProcessInformation.hThread);

    /* Get process and thread ids */
    Service->ProcessId = ProcessInformation.dwProcessId;
    Service->ThreadId = ProcessInformation.dwThreadId;

    /* Resume Thread */
    ResumeThread(ProcessInformation.hThread);

    /* Connect control pipe */
    if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
    {
        DWORD dwProcessId = 0;
        DWORD dwRead = 0;

        DPRINT("Control pipe connected!\n");

        /* Read thread id from pipe */
        if (!ReadFile(Service->ControlPipeHandle,
                      (LPVOID)&dwProcessId,
                      sizeof(DWORD),
                      &dwRead,
                      NULL))
        {
            DPRINT1("Reading the service control pipe failed (Error %lu)\n",
                    GetLastError());
            Status = STATUS_UNSUCCESSFUL;
        }
        else
        {
            DPRINT("Received process id %lu\n", dwProcessId);

            /* FIXME: Send start command */

            Status = STATUS_SUCCESS;
        }
    }
    else
    {
        DPRINT("Connecting control pipe failed!\n");

        /* Close control pipe */
        CloseHandle(Service->ControlPipeHandle);
        Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
        Service->ProcessId = 0;
        Service->ThreadId = 0;
        Status = STATUS_UNSUCCESSFUL;
    }

    ScmSendStartCommand(Service, NULL);

    /* Close process and thread handle */
    CloseHandle(ProcessInformation.hThread);
    CloseHandle(ProcessInformation.hProcess);

    return Status;
}


static NTSTATUS
ScmStartService(PSERVICE Service,
                PSERVICE_GROUP Group)
{
    NTSTATUS Status;

    DPRINT("ScmStartService() called\n");

    Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
    DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);

    if (Service->Status.dwServiceType & SERVICE_DRIVER)
    {
        /* Load driver */
        Status = ScmLoadDriver(Service);
        if (Status == STATUS_SUCCESS)
            Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    }
    else
    {
        /* Start user-mode service */
        Status = ScmStartUserModeService(Service);
    }

    DPRINT("ScmStartService() done (Status %lx)\n", Status);

    if (NT_SUCCESS(Status))
    {
        if (Group != NULL)
        {
            Group->ServicesRunning = TRUE;
        }
        Service->Status.dwCurrentState = SERVICE_RUNNING;
    }
#if 0
    else
    {
        switch (Service->ErrorControl)
        {
            case SERVICE_ERROR_NORMAL:
                /* FIXME: Log error */
                break;

            case SERVICE_ERROR_SEVERE:
                if (IsLastKnownGood == FALSE)
                {
                    /* FIXME: Boot last known good configuration */
                }
                break;

            case SERVICE_ERROR_CRITICAL:
                if (IsLastKnownGood == FALSE)
                {
                    /* FIXME: Boot last known good configuration */
                }
                else
                {
                    /* FIXME: BSOD! */
                }
                break;
        }
    }
#endif

    return Status;
}


VOID
ScmAutoStartServices(VOID)
{
    PLIST_ENTRY GroupEntry;
    PLIST_ENTRY ServiceEntry;
    PSERVICE_GROUP CurrentGroup;
    PSERVICE CurrentService;
    ULONG i;

    /* Clear 'ServiceVisited' flag */
    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
      CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
      CurrentService->ServiceVisited = FALSE;
      ServiceEntry = ServiceEntry->Flink;
    }

    /* Start all services which are members of an existing group */
    GroupEntry = GroupListHead.Flink;
    while (GroupEntry != &GroupListHead)
    {
        CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);

        DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);

        /* Start all services witch have a valid tag */
        for (i = 0; i < CurrentGroup->TagCount; i++)
        {
            ServiceEntry = ServiceListHead.Flink;
            while (ServiceEntry != &ServiceListHead)
            {
                CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

                if ((CurrentService->lpGroup == CurrentGroup) &&
                    (CurrentService->dwStartType == SERVICE_AUTO_START) &&
                    (CurrentService->ServiceVisited == FALSE) &&
                    (CurrentService->dwTag == CurrentGroup->TagArray[i]))
                {
                    CurrentService->ServiceVisited = TRUE;
                    ScmStartService(CurrentService,
                                    CurrentGroup);
                }

                ServiceEntry = ServiceEntry->Flink;
             }
        }

        /* Start all services which have an invalid tag or which do not have a tag */
        ServiceEntry = ServiceListHead.Flink;
        while (ServiceEntry != &ServiceListHead)
        {
            CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

            if ((CurrentService->lpGroup == CurrentGroup) &&
                (CurrentService->dwStartType == SERVICE_AUTO_START) &&
                (CurrentService->ServiceVisited == FALSE))
            {
                CurrentService->ServiceVisited = TRUE;
                ScmStartService(CurrentService,
                                CurrentGroup);
            }

            ServiceEntry = ServiceEntry->Flink;
        }

        GroupEntry = GroupEntry->Flink;
    }

    /* Start all services which are members of any non-existing group */
    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

        if ((CurrentService->lpGroup != NULL) &&
            (CurrentService->dwStartType == SERVICE_AUTO_START) &&
            (CurrentService->ServiceVisited == FALSE))
        {
            CurrentService->ServiceVisited = TRUE;
            ScmStartService(CurrentService,
                            NULL);
        }

        ServiceEntry = ServiceEntry->Flink;
    }

    /* Start all services which are not a member of any group */
    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

        if ((CurrentService->lpGroup == NULL) &&
            (CurrentService->dwStartType == SERVICE_AUTO_START) &&
            (CurrentService->ServiceVisited == FALSE))
        {
            CurrentService->ServiceVisited = TRUE;
            ScmStartService(CurrentService,
                            NULL);
        }

        ServiceEntry = ServiceEntry->Flink;
    }

    /* Clear 'ServiceVisited' flag again */
    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
        CurrentService->ServiceVisited = FALSE;
        ServiceEntry = ServiceEntry->Flink;
    }
}

/* EOF */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?