text: /**************************** Module Header ********************************\
  * Module Name: service.c
  *
  * Copyright (c) 1985 - 1999, Microsoft Corporation
  *
  * Service Support Routines
  *
  * History:
  * 12-22-93 JimA         Created.
  \***************************************************************************/
  
  #include "precomp.h"
  #pragma hdrstop
  
  
  /***************************************************************************\
  * xxxConnectService
  *
  * Open the windowstation assigned to the service logon session. If no
  * windowstation exists, create the windowstation and a default desktop.
  *
  * History:
  * 12-23-93 JimA         Created.
  \***************************************************************************/
  HWINSTA xxxConnectService(
      PUNICODE_STRING pstrWinSta,
      HDESK *phdesk)
  {
      NTSTATUS Status;
      HANDLE hToken;
      ULONG ulLength;
      PTOKEN_USER ptuService;
      PSECURITY_DESCRIPTOR psdService;
      PSID psid;
      PACCESS_ALLOWED_ACE paceService = NULL, pace;
      OBJECT_ATTRIBUTES ObjService;
      HWINSTA hwinsta;
      UNICODE_STRING strDesktop;
      TL tlPoolSdService, tlPoolAceService, tlPoolToken;
  
      /*
       * Open the token of the service.
       */
      Status = OpenEffectiveToken(&hToken);
      if (!NT_SUCCESS(Status)) {
          RIPMSG1(RIP_WARNING, "ConnectService: Could not open process/thread token (0x%X)", Status);
          return NULL;
      }
  
      /*
       * Get the user SID assigned to the service.
       */
      ptuService = NULL;
      paceService = NULL;
      psdService = NULL;
      hwinsta = NULL;
      ZwQueryInformationToken(hToken, TokenUser, NULL, 0, &ulLength);
      ptuService = (PTOKEN_USER)UserAllocPool(ulLength, TAG_TOKEN);
      if (ptuService == NULL) {
          RIPMSG1(RIP_WARNING, "ConnectService: Can't alloc buffer (size=%d) for token info", ulLength);
          ZwClose(hToken);
          goto sd_error;
      }
      Status = ZwQueryInformationToken(hToken, TokenUser, ptuService,
              ulLength, &ulLength);
      ZwClose(hToken);
      if (!NT_SUCCESS(Status)) {
          RIPMSG1(RIP_WARNING, "ConnectService: QueryInformationToken failed (0x%X)", Status);
          goto sd_error;
      }
      psid = ptuService->User.Sid;
  
      /*
       * Create ACE list.
       */
      paceService = AllocAce(NULL, ACCESS_ALLOWED_ACE_TYPE, 0,
              WINSTA_CREATEDESKTOP | WINSTA_READATTRIBUTES |
                  WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS |
                  WINSTA_ACCESSCLIPBOARD | STANDARD_RIGHTS_REQUIRED,
              psid, &ulLength);
      if (paceService == NULL) {
          RIPMSG0(RIP_WARNING, "ConnectService: AllocAce for WindowStation attributes failed");
          goto sd_error;
      }
      pace = AllocAce(paceService, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE |
              INHERIT_ONLY_ACE | NO_PROPAGATE_INHERIT_ACE,
              DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS | DESKTOP_ENUMERATE |
                  DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL |
                  STANDARD_RIGHTS_REQUIRED,
              psid, &ulLength);
      if (pace == NULL) {
          RIPMSG0(RIP_WARNING, "ConnectService: AllocAce for Desktop Attributes failed");
          goto sd_error;
      }
      paceService = pace;
      pace = AllocAce(pace, ACCESS_ALLOWED_ACE_TYPE, 0,
              WINSTA_ENUMERATE,
              SeExports->SeAliasAdminsSid, &ulLength);
      if (pace == NULL) {
          RIPMSG0(RIP_WARNING, "ConnectService: AllocAce for admin WinSta enumerate failed");
          goto sd_error;
      }
      paceService = pace;
      pace = AllocAce(pace, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE |
              INHERIT_ONLY_ACE | NO_PROPAGATE_INHERIT_ACE,
              DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS | DESKTOP_ENUMERATE,
              SeExports->SeAliasAdminsSid, &ulLength);
      if (pace == NULL) {
          RIPMSG0(RIP_WARNING, "ConnectService: AllocAce for admin Desktop access failed");
          goto sd_error;
      }
      paceService = pace;
  
      /*
       * Initialize the SD
       */
      psdService = CreateSecurityDescriptor(paceService, ulLength, FALSE);
      if (psdService == NULL) {
          RIPMSG0(RIP_WARNING, "ConnectService: CreateSecurityDescriptor failed");
          goto sd_error;
      }
  
      ThreadLockPool(PtiCurrent(), ptuService,  &tlPoolToken);
      ThreadLockPool(PtiCurrent(), paceService, &tlPoolAceService);
      ThreadLockPool(PtiCurrent(), psdService,  &tlPoolSdService);
  
      /*
       * The windowstation does not exist and must be created.
       */
      try {
          InitializeObjectAttributes(&ObjService,
                                     pstrWinSta,
                                     OBJ_OPENIF,
                                     NULL,
                                     psdService);
      } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
            Status = GetExceptionCode();
      }
  
      if (NT_SUCCESS(Status)) {
          hwinsta = xxxCreateWindowStation(&ObjService,
                                           KernelMode,
                                           MAXIMUM_ALLOWED,
                                           NULL,
                                           0,
                                           NULL,
                                           NULL,
                                           0);
      }
  
      if (hwinsta != NULL) {
          TRACE_INIT(("Service windowstation created\n"));
  
          /*
           * We have the windowstation, now create the desktop.  The security
           * descriptor will be inherited from the windowstation.  Save the
           * winsta handle because the access struct may be moved by the
           * desktop creation.
           */
          RtlInitUnicodeString(&strDesktop, TEXT("Default"));
          InitializeObjectAttributes(&ObjService, &strDesktop,
                  OBJ_OPENIF | OBJ_CASE_INSENSITIVE, hwinsta, NULL);
  
          *phdesk = xxxCreateDesktop(&ObjService,
                                     KernelMode,
                                     NULL,
                                     NULL,
                                     0,
                                     MAXIMUM_ALLOWED);
          if (*phdesk == NULL) {
              /*
               * The creation failed so close the windowstation and leave.
               */
              RIPMSGF0(RIP_WARNING, "CreateDesktop('Default') failed.");
  
              ZwClose(hwinsta);
              hwinsta = NULL;
          } else {
              TRACE_INIT(("Default desktop in Service windowstation created\n"));
          }
      } else {
          *phdesk = NULL;
      }
  
      ThreadUnlockPool(PtiCurrent(), &tlPoolSdService);
      ThreadUnlockPool(PtiCurrent(), &tlPoolAceService);
      ThreadUnlockPool(PtiCurrent(), &tlPoolToken);
  
  sd_error:
      if (ptuService != NULL) {
          UserFreePool(ptuService);
      }
  
      if (paceService != NULL) {
          UserFreePool(paceService);
      }
  
      if (psdService != NULL) {
          UserFreePool(psdService);
      }
  
      return hwinsta;
  }
  