text: /*
   * Implementation of the Local Security Authority API
   *
   * Copyright 1999 Juergen Schmied
   * Copyright 2002 Andriy Palamarchuk
   * Copyright 2004 Mike McCormack
   * Copyright 2005 Hans Leidekker
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   */
  
  #include <stdarg.h>
  
  #include "ntstatus.h"
  #define WIN32_NO_STATUS
  #include "windef.h"
  #include "winbase.h"
  #include "winreg.h"
  #include "winternl.h"
  #include "advapi32_misc.h"
  
  #include "wine/debug.h"
  #include "wine/unicode.h"
  
  WINE_DEFAULT_DEBUG_CHANNEL(advapi);
  
  #define ADVAPI_ForceLocalComputer(ServerName, FailureCode) \
      if (!ADVAPI_IsLocalComputer(ServerName)) \
  { \
          FIXME("Action Implemented for local computer only. " \
                "Requested for server %s\n", debugstr_w(ServerName)); \
          return FailureCode; \
  }
  
  static void dumpLsaAttributes(const LSA_OBJECT_ATTRIBUTES *oa)
  {
      if (oa)
      {
          TRACE("\n\tlength=%u, rootdir=%p, objectname=%s\n\tattr=0x%08x, sid=%s qos=%p\n",
                oa->Length, oa->RootDirectory,
                oa->ObjectName?debugstr_w(oa->ObjectName->Buffer):"null",
                oa->Attributes, debugstr_sid(oa->SecurityDescriptor),
                oa->SecurityQualityOfService);
      }
  }
  
  static void* ADVAPI_GetDomainName(unsigned sz, unsigned ofs)
  {
      HKEY key;
      LONG ret;
      BYTE* ptr = NULL;
      UNICODE_STRING* ustr;
  
      static const WCHAR wVNETSUP[] = {
          'S','y','s','t','e','m','\\',
          'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
          'S','e','r','v','i','c','e','s','\\',
          'V','x','D','\\','V','N','E','T','S','U','P','\0'};
  
      ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wVNETSUP, 0, KEY_READ, &key);
      if (ret == ERROR_SUCCESS)
      {
          DWORD size = 0;
          static const WCHAR wg[] = { 'W','o','r','k','g','r','o','u','p',0 };
  
          ret = RegQueryValueExW(key, wg, NULL, NULL, NULL, &size);
          if (ret == ERROR_MORE_DATA || ret == ERROR_SUCCESS)
          {
              ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz + size);
              if (!ptr) return NULL;
              ustr = (UNICODE_STRING*)(ptr + ofs);
              ustr->MaximumLength = size;
              ustr->Buffer = (WCHAR*)(ptr + sz);
              ret = RegQueryValueExW(key, wg, NULL, NULL, (LPBYTE)ustr->Buffer, &size);
              if (ret != ERROR_SUCCESS)
              {
                  HeapFree(GetProcessHeap(), 0, ptr);
                  ptr = NULL;
              }   
              else ustr->Length = size - sizeof(WCHAR);
          }
          RegCloseKey(key);
      }
      if (!ptr)
      {
          static const WCHAR wDomain[] = {'D','O','M','A','I','N','\0'};
          ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                          sz + sizeof(wDomain));
          if (!ptr) return NULL;
          ustr = (UNICODE_STRING*)(ptr + ofs);
          ustr->MaximumLength = sizeof(wDomain);
          ustr->Buffer = (WCHAR*)(ptr + sz);
          ustr->Length = sizeof(wDomain) - sizeof(WCHAR);
          memcpy(ustr->Buffer, wDomain, sizeof(wDomain));
      }
      return ptr;
  }
  
  /******************************************************************************
   * LsaAddAccountRights [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaAddAccountRights(
      LSA_HANDLE policy,
      PSID sid,
      PLSA_UNICODE_STRING rights,
      ULONG count)
  {
      FIXME("(%p,%p,%p,0x%08x) stub\n", policy, sid, rights, count);
      return STATUS_OBJECT_NAME_NOT_FOUND;
  }
  
  /******************************************************************************
   * LsaClose [ADVAPI32.@]
   *
   * Closes a handle to a Policy or TrustedDomain.
   *
   * PARAMS
   *  ObjectHandle [I] Handle to a Policy or TrustedDomain.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS.
   *  Failure: NTSTATUS code.
   */
  NTSTATUS WINAPI LsaClose(IN LSA_HANDLE ObjectHandle)
  {
      FIXME("(%p) stub\n", ObjectHandle);
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaCreateTrustedDomainEx [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaCreateTrustedDomainEx(
      LSA_HANDLE policy,
      PTRUSTED_DOMAIN_INFORMATION_EX domain_info,
      PTRUSTED_DOMAIN_AUTH_INFORMATION auth_info,
      ACCESS_MASK access,
      PLSA_HANDLE domain)
  {
      FIXME("(%p,%p,%p,0x%08x,%p) stub\n", policy, domain_info, auth_info,
            access, domain);
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaDeleteTrustedDomain [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaDeleteTrustedDomain(LSA_HANDLE policy, PSID sid)
  {
      FIXME("(%p,%p) stub\n", policy, sid);
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaEnumerateAccountRights [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaEnumerateAccountRights(
      LSA_HANDLE policy,
      PSID sid,
      PLSA_UNICODE_STRING *rights,
      PULONG count)
  {
      FIXME("(%p,%p,%p,%p) stub\n", policy, sid, rights, count);
      *rights = 0;
      *count = 0;
      return STATUS_OBJECT_NAME_NOT_FOUND;
  }
  
  /******************************************************************************
   * LsaEnumerateAccountsWithUserRight [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaEnumerateAccountsWithUserRight(
      LSA_HANDLE policy,
      PLSA_UNICODE_STRING rights,
      PVOID *buffer,
      PULONG count)
  {
      FIXME("(%p,%p,%p,%p) stub\n", policy, rights, buffer, count);
      return STATUS_NO_MORE_ENTRIES;
  }
  
  /******************************************************************************
   * LsaEnumerateTrustedDomains [ADVAPI32.@]
   *
   * Returns the names and SIDs of trusted domains.
   *
   * PARAMS
   *  PolicyHandle          [I] Handle to a Policy object.
   *  EnumerationContext    [I] Pointer to an enumeration handle.
   *  Buffer                [O] Contains the names and SIDs of trusted domains.
   *  PreferredMaximumLength[I] Preferred maximum size in bytes of Buffer.
   *  CountReturned         [O] Number of elements in Buffer.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS,
   *           STATUS_MORE_ENTRIES,
   *           STATUS_NO_MORE_ENTRIES
   *  Failure: NTSTATUS code.
   *
   * NOTES
   *  LsaEnumerateTrustedDomains can be called multiple times to enumerate
   *  all trusted domains.
   */
  NTSTATUS WINAPI LsaEnumerateTrustedDomains(
      IN LSA_HANDLE PolicyHandle,
      IN PLSA_ENUMERATION_HANDLE EnumerationContext,
      OUT PVOID* Buffer,
      IN ULONG PreferredMaximumLength,
      OUT PULONG CountReturned)
  {
      FIXME("(%p,%p,%p,0x%08x,%p) stub\n", PolicyHandle, EnumerationContext,
            Buffer, PreferredMaximumLength, CountReturned);
  
      if (CountReturned) *CountReturned = 0;
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaEnumerateTrustedDomainsEx [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaEnumerateTrustedDomainsEx(
      LSA_HANDLE policy,
      PLSA_ENUMERATION_HANDLE context,
      PVOID *buffer,
      ULONG length,
      PULONG count)
  {
      FIXME("(%p,%p,%p,0x%08x,%p) stub\n", policy, context, buffer, length, count);
  
      if (count) *count = 0;
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaFreeMemory [ADVAPI32.@]
   *
   * Frees memory allocated by a LSA function.
   *
   * PARAMS
   *  Buffer [I] Memory buffer to free.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS.
   *  Failure: NTSTATUS code.
   */
  NTSTATUS WINAPI LsaFreeMemory(IN PVOID Buffer)
  {
      TRACE("(%p)\n", Buffer);
  
      HeapFree(GetProcessHeap(), 0, Buffer);
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaLookupNames [ADVAPI32.@]
   *
   * Returns the SIDs of an array of user, group, or local group names.
   *
   * PARAMS
   *  PolicyHandle      [I] Handle to a Policy object.
   *  Count             [I] Number of names in Names.
   *  Names             [I] Array of names to lookup.
   *  ReferencedDomains [O] Array of domains where the names were found.
   *  Sids              [O] Array of SIDs corresponding to Names.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS,
   *           STATUS_SOME_NOT_MAPPED
   *  Failure: STATUS_NONE_MAPPED or NTSTATUS code.
   */
  NTSTATUS WINAPI LsaLookupNames(
      IN LSA_HANDLE PolicyHandle,
      IN ULONG Count,
      IN PLSA_UNICODE_STRING Names,
      OUT PLSA_REFERENCED_DOMAIN_LIST* ReferencedDomains,
      OUT PLSA_TRANSLATED_SID* Sids)
  {
      FIXME("(%p,0x%08x,%p,%p,%p) stub\n", PolicyHandle, Count, Names,
            ReferencedDomains, Sids);
  
      return STATUS_NONE_MAPPED;
  }
  
  static BOOL lookup_name( LSA_UNICODE_STRING *name, SID *sid, DWORD *sid_size, WCHAR *domain,
                           DWORD *domain_size, SID_NAME_USE *use, BOOL *handled )
  {
      BOOL ret;
  
      ret = lookup_local_wellknown_name( name, sid, sid_size, domain, domain_size, use, handled );
      if (!*handled)
          ret = lookup_local_user_name( name, sid, sid_size, domain, domain_size, use, handled );
  
      return ret;
  }
  
  static INT build_domain(PLSA_REFERENCED_DOMAIN_LIST currentList, PLSA_UNICODE_STRING domain)
  {
      ULONG count;
      ULONG sid_size = 0,domain_size = 0;
      BOOL handled = FALSE;
      SID_NAME_USE use;
  
      for (count = 0; count < currentList->Entries; count ++)
      {
          if ((currentList->Domains[count].Name.Length == domain->Length) &&
              (strncmpiW(currentList->Domains[count].Name.Buffer,domain->Buffer,(domain->Length / sizeof(WCHAR))) == 0))
          {
              HeapFree(GetProcessHeap(),0,domain->Buffer);
              return count;
          }
      }
  
      if (currentList->Entries > 0)
          currentList->Domains = HeapReAlloc(GetProcessHeap(),0,currentList->Domains, (currentList->Entries + 1) * sizeof(LSA_TRUST_INFORMATION));
      else
          currentList->Domains = HeapAlloc(GetProcessHeap(),0,sizeof(LSA_TRUST_INFORMATION));
  
      currentList->Domains[currentList->Entries].Name = *domain;
  
      lookup_name( domain, NULL, &sid_size, NULL, &domain_size, &use, &handled );
      domain_size = 0;
      currentList->Domains[currentList->Entries].Sid = HeapAlloc(GetProcessHeap(),0,sid_size);
      lookup_name( domain, currentList->Domains[currentList->Entries].Sid, &sid_size, NULL, &domain_size, &use, &handled );
  
      currentList->Entries++;
      return currentList->Entries-1;
  }
  
  /******************************************************************************
   * LsaLookupNames2 [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaLookupNames2( LSA_HANDLE policy, ULONG flags, ULONG count,
                                   PLSA_UNICODE_STRING names, PLSA_REFERENCED_DOMAIN_LIST *domains,
                                   PLSA_TRANSLATED_SID2 *sids )
  {
      ULONG i, sid_size_total = 0, domain_size_max = 0, size;
      ULONG sid_size, domain_size, mapped;
      BOOL handled = FALSE;
      SID_NAME_USE use;
      SID *sid;
  
      TRACE("(%p,0x%08x,0x%08x,%p,%p,%p)\n", policy, flags, count, names, domains, sids);
  
      mapped = 0;
      for (i = 0; i < count; i++)
      {
          handled = FALSE;
          sid_size = domain_size = 0;
          lookup_name( &names[i], NULL, &sid_size, NULL, &domain_size, &use, &handled );
          if (handled)
          {
              sid_size_total += sid_size;
              if (domain_size)
              {
                  if (domain_size > domain_size_max)
                      domain_size_max = domain_size;
              }
              mapped++;
          }
      }
      TRACE("mapped %u out of %u\n", mapped, count);
  
      size = sizeof(LSA_TRANSLATED_SID2) * count + sid_size_total;
      if (!(*sids = HeapAlloc( GetProcessHeap(), 0, size) )) return STATUS_NO_MEMORY;
  
      sid = (SID *)(*sids + count);
  
      if (!(*domains = HeapAlloc( GetProcessHeap(), 0, sizeof(LSA_REFERENCED_DOMAIN_LIST) )))
      {
          HeapFree( GetProcessHeap(), 0, *sids );
          return STATUS_NO_MEMORY;
      }
      (*domains)->Entries = 0;
      (*domains)->Domains = NULL;
  
      for (i = 0; i < count; i++)
      {
          LSA_UNICODE_STRING domain;
  
          domain.Length = domain_size_max*sizeof(WCHAR);
          domain.MaximumLength = domain_size_max*sizeof(WCHAR);
          domain.Buffer = HeapAlloc(GetProcessHeap(),0,domain.Length);
  
          (*sids)[i].Use = SidTypeUnknown;
          (*sids)[i].DomainIndex = -1;
          (*sids)[i].Flags = 0;
  
          handled = FALSE;
          sid_size = sid_size_total;
          domain_size = domain_size_max;
          lookup_name( &names[i], sid, &sid_size, domain.Buffer, &domain_size, &use, &handled );
          if (handled)
          {
              (*sids)[i].Sid = sid;
              (*sids)[i].Use = use;
  
              sid = (SID *)((char *)sid + sid_size);
              sid_size_total -= sid_size;
              if (domain_size)
              {
                  domain.Length = domain_size * sizeof(WCHAR);
                  (*sids)[i].DomainIndex = build_domain(*domains, &domain);
              }
              else
                  HeapFree(GetProcessHeap(),0,domain.Buffer);
          }
          else
              HeapFree(GetProcessHeap(),0,domain.Buffer);
      }
  
      if (mapped == count) return STATUS_SUCCESS;
      if (mapped > 0 && mapped < count) return STATUS_SOME_NOT_MAPPED;
      return STATUS_NONE_MAPPED;
  }
  
  /******************************************************************************
   * LsaLookupSids [ADVAPI32.@]
   *
   * Looks up the names that correspond to an array of SIDs.
   *
   * PARAMS
   *  PolicyHandle      [I] Handle to a Policy object.
   *  Count             [I] Number of SIDs in the Sids array.
   *  Sids              [I] Array of SIDs to lookup.
   *  ReferencedDomains [O] Array of domains where the sids were found.
   *  Names             [O] Array of names corresponding to Sids.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS,
   *           STATUS_SOME_NOT_MAPPED
   *  Failure: STATUS_NONE_MAPPED or NTSTATUS code.
   */
  NTSTATUS WINAPI LsaLookupSids(
      IN LSA_HANDLE PolicyHandle,
      IN ULONG Count,
      IN PSID *Sids,
      OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
      OUT PLSA_TRANSLATED_NAME *Names )
  {
      ULONG i, mapped, size;
      ULONG name_size, domain_size;
      SID_NAME_USE use;
  
      TRACE("(%p,%u,%p,%p,%p) stub\n", PolicyHandle, Count, Sids,
            ReferencedDomains, Names);
  
      size = sizeof(LSA_TRANSLATED_NAME) * Count;
      if (!(*Names = HeapAlloc( GetProcessHeap(), 0, size) )) return STATUS_NO_MEMORY;
      if (!(*ReferencedDomains = HeapAlloc( GetProcessHeap(), 0, sizeof(LSA_REFERENCED_DOMAIN_LIST)) ))
      {
          HeapFree( GetProcessHeap(), 0, *Names);
          return STATUS_NO_MEMORY;
      }
      (*ReferencedDomains)->Entries = 0;
      (*ReferencedDomains)->Domains = NULL;
  
      mapped = 0;
      for (i = 0; i < Count; i++)
      {
          name_size = domain_size = 0;
          (*Names)[i].Use = SidTypeUnknown;
          (*Names)[i].DomainIndex = -1;
          (*Names)[i].Name.Length = 0;
          (*Names)[i].Name.MaximumLength = 0;
          (*Names)[i].Name.Buffer = NULL;
  
          if (!LookupAccountSidW(NULL, Sids[i], NULL, &name_size, NULL, &domain_size, &use) &&
              GetLastError() == ERROR_INSUFFICIENT_BUFFER)
          {
              LSA_UNICODE_STRING domain;
  
              mapped++;
  
              if (domain_size)
              {
                  domain.Length = (domain_size - 1) * sizeof(WCHAR);
                  domain.MaximumLength = domain_size*sizeof(WCHAR);
                  domain.Buffer = HeapAlloc(GetProcessHeap(),0,domain.MaximumLength);
              }
              else
              {
                  domain.Length = 0;
                  domain.MaximumLength = 0;
                  domain.Buffer = NULL;
              }
  
              (*Names)[i].Name.Length = (name_size - 1) * sizeof(WCHAR);
              (*Names)[i].Name.MaximumLength = name_size * sizeof(WCHAR);
              (*Names)[i].Name.Buffer = HeapAlloc(GetProcessHeap(), 0, name_size * sizeof(WCHAR));
              LookupAccountSidW(NULL, Sids[i], (*Names)[i].Name.Buffer, &name_size, domain.Buffer, &domain_size, &use);
              (*Names)[i].Use = use;
  
              if (domain_size)
                  (*Names)[i].DomainIndex = build_domain(*ReferencedDomains, &domain);
          }
      }
      TRACE("mapped %u out of %u\n",mapped,Count);
  
      if (mapped == Count) return STATUS_SUCCESS;
      if (mapped) return STATUS_SOME_NOT_MAPPED;
      return STATUS_NONE_MAPPED;
  }
  
  /******************************************************************************
   * LsaNtStatusToWinError [ADVAPI32.@]
   *
   * Converts an LSA NTSTATUS code to a Windows error code.
   *
   * PARAMS
   *  Status [I] NTSTATUS code.
   *
   * RETURNS
   *  Success: Corresponding Windows error code.
   *  Failure: ERROR_MR_MID_NOT_FOUND.
   */
  ULONG WINAPI LsaNtStatusToWinError(NTSTATUS Status)
  {
      return RtlNtStatusToDosError(Status);
  }
  
  /******************************************************************************
   * LsaOpenPolicy [ADVAPI32.@]
   *
   * Opens a handle to the Policy object on a local or remote system.
   *
   * PARAMS
   *  SystemName       [I] Name of the target system.
   *  ObjectAttributes [I] Connection attributes.
   *  DesiredAccess    [I] Requested access rights.
   *  PolicyHandle     [I/O] Handle to the Policy object.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS.
   *  Failure: NTSTATUS code.
   *
   * NOTES
   *  Set SystemName to NULL to open the local Policy object.
   */
  NTSTATUS WINAPI LsaOpenPolicy(
      IN PLSA_UNICODE_STRING SystemName,
      IN PLSA_OBJECT_ATTRIBUTES ObjectAttributes,
      IN ACCESS_MASK DesiredAccess,
      IN OUT PLSA_HANDLE PolicyHandle)
  {
      FIXME("(%s,%p,0x%08x,%p) stub\n",
            SystemName?debugstr_w(SystemName->Buffer):"(null)",
            ObjectAttributes, DesiredAccess, PolicyHandle);
  
      ADVAPI_ForceLocalComputer(SystemName ? SystemName->Buffer : NULL,
                                STATUS_ACCESS_VIOLATION);
      dumpLsaAttributes(ObjectAttributes);
  
      if(PolicyHandle) *PolicyHandle = (LSA_HANDLE)0xcafe;
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaOpenTrustedDomainByName [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaOpenTrustedDomainByName(
      LSA_HANDLE policy,
      PLSA_UNICODE_STRING name,
      ACCESS_MASK access,
      PLSA_HANDLE handle)
  {
      FIXME("(%p,%p,0x%08x,%p) stub\n", policy, name, access, handle);
      return STATUS_OBJECT_NAME_NOT_FOUND;
  }
  
  /******************************************************************************
   * LsaQueryInformationPolicy [ADVAPI32.@]
   *
   * Returns information about a Policy object.
   *
   * PARAMS
   *  PolicyHandle     [I] Handle to a Policy object.
   *  InformationClass [I] Type of information to retrieve.
   *  Buffer           [O] Pointer to the requested information.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS.
   *  Failure: NTSTATUS code.
   */
  NTSTATUS WINAPI LsaQueryInformationPolicy(
      IN LSA_HANDLE PolicyHandle,
      IN POLICY_INFORMATION_CLASS InformationClass,
      OUT PVOID *Buffer)
  {
      TRACE("(%p,0x%08x,%p)\n", PolicyHandle, InformationClass, Buffer);
  
      if(!Buffer) return STATUS_INVALID_PARAMETER;
      switch (InformationClass)
      {
          case PolicyAuditEventsInformation: /* 2 */
          {
              PPOLICY_AUDIT_EVENTS_INFO p = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                                      sizeof(POLICY_AUDIT_EVENTS_INFO));
              p->AuditingMode = FALSE; /* no auditing */
              *Buffer = p;
          }
          break;
          case PolicyPrimaryDomainInformation: /* 3 */
          {
              /* Only the domain name is valid for the local computer.
               * All other fields are zero.
               */
              PPOLICY_PRIMARY_DOMAIN_INFO pinfo;
  
              pinfo = ADVAPI_GetDomainName(sizeof(*pinfo), offsetof(POLICY_PRIMARY_DOMAIN_INFO, Name));
  
              TRACE("setting domain to %s\n", debugstr_w(pinfo->Name.Buffer));
  
              *Buffer = pinfo;
          }
          break;
          case PolicyAccountDomainInformation: /* 5 */
          {
              struct di
              {
                  POLICY_ACCOUNT_DOMAIN_INFO info;
                  SID sid;
                  DWORD padding[3];
                  WCHAR domain[MAX_COMPUTERNAME_LENGTH + 1];
              };
  
              DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
              struct di * xdi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*xdi));
  
              xdi->info.DomainName.MaximumLength = dwSize * sizeof(WCHAR);
              xdi->info.DomainName.Buffer = xdi->domain;
              if (GetComputerNameW(xdi->info.DomainName.Buffer, &dwSize))
                  xdi->info.DomainName.Length = dwSize * sizeof(WCHAR);
  
              TRACE("setting name to %s\n", debugstr_w(xdi->info.DomainName.Buffer));
  
              xdi->info.DomainSid = &xdi->sid;
  
              if (!ADVAPI_GetComputerSid(&xdi->sid))
              {
                  HeapFree(GetProcessHeap(), 0, xdi);
  
                  WARN("Computer SID not found\n");
  
                  return STATUS_UNSUCCESSFUL;
              }
  
              TRACE("setting SID to %s\n", debugstr_sid(&xdi->sid));
  
              *Buffer = xdi;
          }
          break;
          case  PolicyDnsDomainInformation:	/* 12 (0xc) */
          {
              /* Only the domain name is valid for the local computer.
               * All other fields are zero.
               */
              PPOLICY_DNS_DOMAIN_INFO pinfo;
  
              pinfo = ADVAPI_GetDomainName(sizeof(*pinfo), offsetof(POLICY_DNS_DOMAIN_INFO, Name));
  
              TRACE("setting domain to %s\n", debugstr_w(pinfo->Name.Buffer));
  
              *Buffer = pinfo;
          }
          break;
          case  PolicyAuditLogInformation:
          case  PolicyPdAccountInformation:
          case  PolicyLsaServerRoleInformation:
          case  PolicyReplicaSourceInformation:
          case  PolicyDefaultQuotaInformation:
          case  PolicyModificationInformation:
          case  PolicyAuditFullSetInformation:
          case  PolicyAuditFullQueryInformation:
          {
              FIXME("category %d not implemented\n", InformationClass);
              return STATUS_UNSUCCESSFUL;
          }
      }
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaQueryTrustedDomainInfo [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaQueryTrustedDomainInfo(
      LSA_HANDLE policy,
      PSID sid,
      TRUSTED_INFORMATION_CLASS class,
      PVOID *buffer)
  {
      FIXME("(%p,%p,%d,%p) stub\n", policy, sid, class, buffer);
      return STATUS_OBJECT_NAME_NOT_FOUND;
  }
  
  /******************************************************************************
   * LsaQueryTrustedDomainInfoByName [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaQueryTrustedDomainInfoByName(
      LSA_HANDLE policy,
      PLSA_UNICODE_STRING name,
      TRUSTED_INFORMATION_CLASS class,
      PVOID *buffer)
  {
      FIXME("(%p,%p,%d,%p) stub\n", policy, name, class, buffer);
      return STATUS_OBJECT_NAME_NOT_FOUND;
  }
  
  /******************************************************************************
   * LsaRegisterPolicyChangeNotification [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaRegisterPolicyChangeNotification(
      POLICY_NOTIFICATION_INFORMATION_CLASS class,
      HANDLE event)
  {
      FIXME("(%d,%p) stub\n", class, event);
      return STATUS_UNSUCCESSFUL;
  }
  
  /******************************************************************************
   * LsaRemoveAccountRights [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaRemoveAccountRights(
      LSA_HANDLE policy,
      PSID sid,
      BOOLEAN all,
      PLSA_UNICODE_STRING rights,
      ULONG count)
  {
      FIXME("(%p,%p,%d,%p,0x%08x) stub\n", policy, sid, all, rights, count);
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaRetrievePrivateData [ADVAPI32.@]
   *
   * Retrieves data stored by LsaStorePrivateData.
   *
   * PARAMS
   *  PolicyHandle [I] Handle to a Policy object.
   *  KeyName      [I] Name of the key where the data is stored.
   *  PrivateData  [O] Pointer to the private data.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS.
   *  Failure: STATUS_OBJECT_NAME_NOT_FOUND or NTSTATUS code.
   */
  NTSTATUS WINAPI LsaRetrievePrivateData(
      IN LSA_HANDLE PolicyHandle,
      IN PLSA_UNICODE_STRING KeyName,
      OUT PLSA_UNICODE_STRING* PrivateData)
  {
      FIXME("(%p,%p,%p) stub\n", PolicyHandle, KeyName, PrivateData);
      return STATUS_OBJECT_NAME_NOT_FOUND;
  }
  
  /******************************************************************************
   * LsaSetInformationPolicy [ADVAPI32.@]
   *
   * Modifies information in a Policy object.
   *
   * PARAMS
   *  PolicyHandle     [I] Handle to a Policy object.
   *  InformationClass [I] Type of information to set.
   *  Buffer           [I] Pointer to the information to set.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS.
   *  Failure: NTSTATUS code.
   */
  NTSTATUS WINAPI LsaSetInformationPolicy(
      IN LSA_HANDLE PolicyHandle,
      IN POLICY_INFORMATION_CLASS InformationClass,
      IN PVOID Buffer)
  {
      FIXME("(%p,0x%08x,%p) stub\n", PolicyHandle, InformationClass, Buffer);
  
      return STATUS_UNSUCCESSFUL;
  }
  
  /******************************************************************************
   * LsaSetSecret [ADVAPI32.@]
   *
   * Set old and new values on a secret handle
   *
   * PARAMS
   *  SecretHandle          [I] Handle to a secret object.
   *  EncryptedCurrentValue [I] Pointer to encrypted new value, can be NULL
   *  EncryptedOldValue     [I] Pointer to encrypted old value, can be NULL
   *
   * RETURNS
   *  Success: STATUS_SUCCESS
   *  Failure: NTSTATUS code.
   */
  NTSTATUS WINAPI LsaSetSecret(
      IN LSA_HANDLE SecretHandle,
      IN PLSA_UNICODE_STRING EncryptedCurrentValue,
      IN PLSA_UNICODE_STRING EncryptedOldValue)
  {
      FIXME("(%p,%p,%p) stub\n", SecretHandle, EncryptedCurrentValue,
              EncryptedOldValue);
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaSetTrustedDomainInfoByName [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaSetTrustedDomainInfoByName(
      LSA_HANDLE policy,
      PLSA_UNICODE_STRING name,
      TRUSTED_INFORMATION_CLASS class,
      PVOID buffer)
  {
      FIXME("(%p,%p,%d,%p) stub\n", policy, name, class, buffer);
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaSetTrustedDomainInformation [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaSetTrustedDomainInformation(
      LSA_HANDLE policy,
      PSID sid,
      TRUSTED_INFORMATION_CLASS class,
      PVOID buffer)
  {
      FIXME("(%p,%p,%d,%p) stub\n", policy, sid, class, buffer);
      return STATUS_SUCCESS;
  }
  
  /******************************************************************************
   * LsaStorePrivateData [ADVAPI32.@]
   *
   * Stores or deletes a Policy object's data under the specified reg key.
   *
   * PARAMS
   *  PolicyHandle [I] Handle to a Policy object.
   *  KeyName      [I] Name of the key where the data will be stored.
   *  PrivateData  [O] Pointer to the private data.
   *
   * RETURNS
   *  Success: STATUS_SUCCESS.
   *  Failure: STATUS_OBJECT_NAME_NOT_FOUND or NTSTATUS code.
   */
  NTSTATUS WINAPI LsaStorePrivateData(
      IN LSA_HANDLE PolicyHandle,
      IN PLSA_UNICODE_STRING KeyName,
      IN PLSA_UNICODE_STRING PrivateData)
  {
      FIXME("(%p,%p,%p) stub\n", PolicyHandle, KeyName, PrivateData);
      return STATUS_OBJECT_NAME_NOT_FOUND;
  }
  
  /******************************************************************************
   * LsaUnregisterPolicyChangeNotification [ADVAPI32.@]
   *
   */
  NTSTATUS WINAPI LsaUnregisterPolicyChangeNotification(
      POLICY_NOTIFICATION_INFORMATION_CLASS class,
      HANDLE event)
  {
      FIXME("(%d,%p) stub\n", class, event);
      return STATUS_SUCCESS;
  }
  