1// Windows/SecurityUtils.cpp
2
3#include "StdAfx.h"
4
5#include "SecurityUtils.h"
6
7namespace NWindows {
8namespace NSecurity {
9
10/*
11bool MyLookupAccountSid(LPCTSTR systemName, PSID sid,
12  CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse)
13{
14  DWORD accountNameSize = 0, domainNameSize = 0;
15
16  if (!::LookupAccountSid(systemName, sid,
17      accountName.GetBuf(0), &accountNameSize,
18      domainName.GetBuf(0), &domainNameSize, sidNameUse))
19  {
20    if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
21      return false;
22  }
23  DWORD accountNameSize2 = accountNameSize, domainNameSize2 = domainNameSize;
24  bool result = BOOLToBool(::LookupAccountSid(systemName, sid,
25      accountName.GetBuf(accountNameSize), &accountNameSize2,
26      domainName.GetBuf(domainNameSize), &domainNameSize2, sidNameUse));
27  accountName.ReleaseBuf_CalcLen(accountNameSize);
28  domainName.ReleaseBuf_CalcLen(domainNameSize);
29  return result;
30}
31*/
32
33static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest)
34{
35  const size_t len = (size_t)wcslen(src);
36  dest->Length = (USHORT)(len * sizeof(WCHAR));
37  dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR));
38  dest->Buffer = src;
39}
40
41/*
42static void MyLookupSids(CPolicy &policy, PSID ps)
43{
44  LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL;
45  LSA_TRANSLATED_NAME *names = NULL;
46  NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names);
47  int res = LsaNtStatusToWinError(nts);
48  LsaFreeMemory(referencedDomains);
49  LsaFreeMemory(names);
50}
51*/
52
53extern "C" {
54
55#ifndef _UNICODE
56typedef BOOL (WINAPI * Func_LookupAccountNameW)(
57    LPCWSTR lpSystemName,
58    LPCWSTR lpAccountName,
59    PSID Sid,
60    LPDWORD cbSid,
61    LPWSTR ReferencedDomainName,
62    LPDWORD cchReferencedDomainName,
63    PSID_NAME_USE peUse
64    );
65#endif
66
67}
68
69static PSID GetSid(LPWSTR accountName)
70{
71  #ifndef _UNICODE
72  const HMODULE hModule = GetModuleHandle(TEXT("advapi32.dll"));
73  if (!hModule)
74    return NULL;
75  const
76  Func_LookupAccountNameW lookupAccountNameW = Z7_GET_PROC_ADDRESS(
77  Func_LookupAccountNameW, hModule,
78      "LookupAccountNameW");
79  if (!lookupAccountNameW)
80    return NULL;
81  #endif
82
83  DWORD sidLen = 0, domainLen = 0;
84  SID_NAME_USE sidNameUse;
85  if (!
86    #ifdef _UNICODE
87    ::LookupAccountNameW
88    #else
89      lookupAccountNameW
90    #endif
91        (NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse))
92  {
93    if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
94    {
95      const PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen);
96      LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR));
97      const BOOL res =
98        #ifdef _UNICODE
99        ::LookupAccountNameW
100        #else
101          lookupAccountNameW
102        #endif
103            (NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse);
104      ::HeapFree(GetProcessHeap(), 0, domainName);
105      if (res)
106        return pSid;
107    }
108  }
109  return NULL;
110}
111
112#define Z7_WIN_SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege"
113
114bool AddLockMemoryPrivilege()
115{
116  CPolicy policy;
117  LSA_OBJECT_ATTRIBUTES attr;
118  attr.Length = sizeof(attr);
119  attr.RootDirectory = NULL;
120  attr.ObjectName  = NULL;
121  attr.Attributes = 0;
122  attr.SecurityDescriptor = NULL;
123  attr.SecurityQualityOfService  = NULL;
124  if (policy.Open(NULL, &attr,
125      // GENERIC_WRITE)
126      POLICY_ALL_ACCESS)
127      // STANDARD_RIGHTS_REQUIRED,
128      // GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES)
129      != 0)
130    return false;
131  LSA_UNICODE_STRING userRights;
132  wchar_t s[128] = Z7_WIN_SE_LOCK_MEMORY_NAME;
133  SetLsaString(s, &userRights);
134  WCHAR userName[256 + 2];
135  DWORD size = 256;
136  if (!GetUserNameW(userName, &size))
137    return false;
138  const PSID psid = GetSid(userName);
139  if (psid == NULL)
140    return false;
141  bool res = false;
142
143  /*
144  PLSA_UNICODE_STRING userRightsArray;
145  ULONG countOfRights;
146  NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights);
147  if (status != 0)
148    return false;
149  bool finded = false;
150  for (ULONG i = 0; i < countOfRights; i++)
151  {
152    LSA_UNICODE_STRING &ur = userRightsArray[i];
153    if (ur.Length != s.Length() * sizeof(WCHAR))
154      continue;
155    if (wcsncmp(ur.Buffer, s, s.Length()) != 0)
156      continue;
157    finded = true;
158    res = true;
159    break;
160  }
161  if (!finded)
162  */
163  {
164    /*
165    LSA_ENUMERATION_INFORMATION *enums;
166    ULONG countReturned;
167    NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned);
168    if (status == 0)
169    {
170      for (ULONG i = 0; i < countReturned; i++)
171        MyLookupSids(policy, enums[i].Sid);
172      if (enums)
173        ::LsaFreeMemory(enums);
174      res = true;
175    }
176    */
177    const NTSTATUS status = policy.AddAccountRights(psid, &userRights);
178    if (status == 0)
179      res = true;
180    // ULONG res = LsaNtStatusToWinError(status);
181  }
182  HeapFree(GetProcessHeap(), 0, psid);
183  return res;
184}
185
186}}
187