Process Hacker
lsa.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * LSA support functions
4  *
5  * Copyright (C) 2010-2011 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /*
24  * These are functions which communicate with LSA or are support functions.
25  * They replace certain Win32 security-related functions such as
26  * LookupAccountName, LookupAccountSid and LookupPrivilege*, which are
27  * badly designed. (LSA already allocates the return values for the caller,
28  * yet the Win32 functions insist on their callers providing their own
29  * buffers.)
30  */
31 
32 #include <ph.h>
33 
34 static LSA_HANDLE PhLookupPolicyHandle = NULL;
35 
36 NTSTATUS PhOpenLsaPolicy(
37  _Out_ PLSA_HANDLE PolicyHandle,
38  _In_ ACCESS_MASK DesiredAccess,
39  _In_opt_ PUNICODE_STRING SystemName
40  )
41 {
42  OBJECT_ATTRIBUTES oa = { 0 };
43 
44  return LsaOpenPolicy(
45  SystemName,
46  &oa,
47  DesiredAccess,
48  PolicyHandle
49  );
50 }
51 
59  VOID
60  )
61 {
62  LSA_HANDLE lookupPolicyHandle;
63  LSA_HANDLE newLookupPolicyHandle;
64 
65  lookupPolicyHandle = PhLookupPolicyHandle;
66 
67  // If there is no cached handle, open one.
68 
69  if (!lookupPolicyHandle)
70  {
72  &newLookupPolicyHandle,
73  POLICY_LOOKUP_NAMES,
74  NULL
75  )))
76  {
77  // We succeeded in opening a policy handle,
78  // and since we did not have a cached handle
79  // before, we will now store it.
80 
81  lookupPolicyHandle = _InterlockedCompareExchangePointer(
82  &PhLookupPolicyHandle,
83  newLookupPolicyHandle,
84  NULL
85  );
86 
87  if (!lookupPolicyHandle)
88  {
89  // Success. Use our handle.
90  lookupPolicyHandle = newLookupPolicyHandle;
91  }
92  else
93  {
94  // Someone already placed a handle in the
95  // cache. Close our handle and use their
96  // handle.
97  LsaClose(newLookupPolicyHandle);
98  }
99  }
100  }
101 
102  return lookupPolicyHandle;
103 }
104 
115  _In_ PLUID PrivilegeValue,
116  _Out_ PPH_STRING *PrivilegeName
117  )
118 {
119  NTSTATUS status;
120  PUNICODE_STRING name;
121 
122  status = LsaLookupPrivilegeName(
124  PrivilegeValue,
125  &name
126  );
127 
128  if (!NT_SUCCESS(status))
129  return FALSE;
130 
131  *PrivilegeName = PhCreateStringFromUnicodeString(name);
132  LsaFreeMemory(name);
133 
134  return TRUE;
135 }
136 
147  _In_ PPH_STRINGREF PrivilegeName,
148  _Out_ PPH_STRING *PrivilegeDisplayName
149  )
150 {
151  NTSTATUS status;
152  UNICODE_STRING privilegeName;
153  PUNICODE_STRING displayName;
154  SHORT language;
155 
156  PhStringRefToUnicodeString(PrivilegeName, &privilegeName);
157 
160  &privilegeName,
161  &displayName,
162  &language
163  );
164 
165  if (!NT_SUCCESS(status))
166  return FALSE;
167 
168  *PrivilegeDisplayName = PhCreateStringFromUnicodeString(displayName);
169  LsaFreeMemory(displayName);
170 
171  return TRUE;
172 }
173 
182  _In_ PPH_STRINGREF PrivilegeName,
183  _Out_ PLUID PrivilegeValue
184  )
185 {
186  UNICODE_STRING privilegeName;
187 
188  PhStringRefToUnicodeString(PrivilegeName, &privilegeName);
189 
192  &privilegeName,
193  PrivilegeValue
194  ));
195 }
196 
212 NTSTATUS PhLookupSid(
213  _In_ PSID Sid,
214  _Out_opt_ PPH_STRING *Name,
215  _Out_opt_ PPH_STRING *DomainName,
216  _Out_opt_ PSID_NAME_USE NameUse
217  )
218 {
219  NTSTATUS status;
220  LSA_HANDLE policyHandle;
221  PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
222  PLSA_TRANSLATED_NAME names;
223 
224  policyHandle = PhGetLookupPolicyHandle();
225 
226  referencedDomains = NULL;
227  names = NULL;
228 
229  if (NT_SUCCESS(status = LsaLookupSids(
230  policyHandle,
231  1,
232  &Sid,
233  &referencedDomains,
234  &names
235  )))
236  {
237  if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)
238  {
239  if (Name)
240  {
241  *Name = PhCreateStringFromUnicodeString(&names[0].Name);
242  }
243 
244  if (DomainName)
245  {
246  if (names[0].DomainIndex >= 0)
247  {
248  PLSA_TRUST_INFORMATION trustInfo;
249 
250  trustInfo = &referencedDomains->Domains[names[0].DomainIndex];
251  *DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);
252  }
253  else
254  {
255  *DomainName = PhReferenceEmptyString();
256  }
257  }
258 
259  if (NameUse)
260  {
261  *NameUse = names[0].Use;
262  }
263  }
264  else
265  {
266  status = STATUS_NONE_MAPPED;
267  }
268  }
269 
270  // LsaLookupSids allocates memory even if it returns STATUS_NONE_MAPPED.
271  if (referencedDomains)
272  LsaFreeMemory(referencedDomains);
273  if (names)
274  LsaFreeMemory(names);
275 
276  return status;
277 }
278 
293 NTSTATUS PhLookupName(
294  _In_ PPH_STRINGREF Name,
295  _Out_opt_ PSID *Sid,
296  _Out_opt_ PPH_STRING *DomainName,
297  _Out_opt_ PSID_NAME_USE NameUse
298  )
299 {
300  NTSTATUS status;
301  LSA_HANDLE policyHandle;
302  UNICODE_STRING name;
303  PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
304  PLSA_TRANSLATED_SID2 sids;
305 
306  policyHandle = PhGetLookupPolicyHandle();
307 
308  PhStringRefToUnicodeString(Name, &name);
309 
310  referencedDomains = NULL;
311  sids = NULL;
312 
313  if (NT_SUCCESS(status = LsaLookupNames2(
314  policyHandle,
315  0,
316  1,
317  &name,
318  &referencedDomains,
319  &sids
320  )))
321  {
322  if (sids[0].Use != SidTypeInvalid && sids[0].Use != SidTypeUnknown)
323  {
324  if (Sid)
325  {
326  PSID sid;
327  ULONG sidLength;
328 
329  sidLength = RtlLengthSid(sids[0].Sid);
330  sid = PhAllocate(sidLength);
331  memcpy(sid, sids[0].Sid, sidLength);
332 
333  *Sid = sid;
334  }
335 
336  if (DomainName)
337  {
338  if (sids[0].DomainIndex >= 0)
339  {
340  PLSA_TRUST_INFORMATION trustInfo;
341 
342  trustInfo = &referencedDomains->Domains[sids[0].DomainIndex];
343  *DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);
344  }
345  else
346  {
347  *DomainName = PhReferenceEmptyString();
348  }
349  }
350 
351  if (NameUse)
352  {
353  *NameUse = sids[0].Use;
354  }
355  }
356  else
357  {
358  status = STATUS_NONE_MAPPED;
359  }
360  }
361 
362  // LsaLookupNames2 allocates memory even if it returns STATUS_NONE_MAPPED.
363  if (referencedDomains)
364  LsaFreeMemory(referencedDomains);
365  if (sids)
366  LsaFreeMemory(sids);
367 
368  return status;
369 }
370 
388  _In_ PSID Sid,
389  _In_ BOOLEAN IncludeDomain,
390  _Out_opt_ PSID_NAME_USE NameUse
391  )
392 {
393  NTSTATUS status;
394  PPH_STRING fullName;
395  LSA_HANDLE policyHandle;
396  PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
397  PLSA_TRANSLATED_NAME names;
398 
399  policyHandle = PhGetLookupPolicyHandle();
400 
401  referencedDomains = NULL;
402  names = NULL;
403 
404  if (NT_SUCCESS(status = LsaLookupSids(
405  policyHandle,
406  1,
407  &Sid,
408  &referencedDomains,
409  &names
410  )))
411  {
412  if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)
413  {
414  PWSTR domainNameBuffer;
415  ULONG domainNameLength;
416 
417  if (IncludeDomain && names[0].DomainIndex >= 0)
418  {
419  PLSA_TRUST_INFORMATION trustInfo;
420 
421  trustInfo = &referencedDomains->Domains[names[0].DomainIndex];
422  domainNameBuffer = trustInfo->Name.Buffer;
423  domainNameLength = trustInfo->Name.Length;
424  }
425  else
426  {
427  domainNameBuffer = NULL;
428  domainNameLength = 0;
429  }
430 
431  if (domainNameBuffer && domainNameLength != 0)
432  {
433  fullName = PhCreateStringEx(NULL, domainNameLength + sizeof(WCHAR) + names[0].Name.Length);
434  memcpy(&fullName->Buffer[0], domainNameBuffer, domainNameLength);
435  fullName->Buffer[domainNameLength / sizeof(WCHAR)] = '\\';
436  memcpy(&fullName->Buffer[domainNameLength / sizeof(WCHAR) + 1], names[0].Name.Buffer, names[0].Name.Length);
437  }
438  else
439  {
440  fullName = PhCreateStringFromUnicodeString(&names[0].Name);
441  }
442 
443  if (NameUse)
444  {
445  *NameUse = names[0].Use;
446  }
447  }
448  else
449  {
450  fullName = NULL;
451  }
452  }
453  else
454  {
455  fullName = NULL;
456  }
457 
458  if (referencedDomains)
459  LsaFreeMemory(referencedDomains);
460  if (names)
461  LsaFreeMemory(names);
462 
463  return fullName;
464 }
465 
478  _In_ PSID Sid
479  )
480 {
481  PPH_STRING string;
482  UNICODE_STRING us;
483 
484  string = PhCreateStringEx(NULL, MAX_UNICODE_STACK_BUFFER_LENGTH * sizeof(WCHAR));
485  PhStringRefToUnicodeString(&string->sr, &us);
486 
488  &us,
489  Sid,
490  FALSE
491  )))
492  {
493  string->Length = us.Length;
494  string->Buffer[us.Length / sizeof(WCHAR)] = 0;
495 
496  return string;
497  }
498  else
499  {
500  return NULL;
501  }
502 }