uLib  User mode C/C++ extended API library for Win32 programmers.
UmLsa.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - User mode library.
3 // Module: User mode LSA based functions and helpful security subroutines.
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 
8 #include <uLib/UtilFunc.h>
9 #include <uLib/StrFunc.h>
10 #include <uLib/Debug.h>
11 
12 #define _INIT_FP_ 1
13 #include <uLib/UmLsa.h>
14 
15 // Initialize function pointers to some LSA APIs that are not exported
16 // in AdvApi32.lib. Some of them have no alternatives.
17 // These were previously only accesible via NtLsa.h, ergo not in user mode.
18 
20 {
21  static CCSTR ModName = _T("ADVAPI32");
22 
23  bool ok = (_LsaOpenAccount != NULL); // Use this as "initialized" flag.
24  if ( !ok )
25  {
26  HMODULE hMod = GetModuleHandle( ModName ); // Already loaded?
27  if (!hMod) hMod = LoadLibrary( ModName ); // No.. Load it now.
28 
29  ok = (hMod != NULL);
30  if (ok)
31  {
32  LONG_PTR anyPtr = 0;
33  // Account
34  INIT_LSAFUNC( LsaOpenAccount );
35  INIT_LSAFUNC( LsaCreateAccount );
36  INIT_LSAFUNC( LsaEnumerateAccounts );
37  INIT_LSAFUNC( LsaGetSystemAccessAccount );
38  INIT_LSAFUNC( LsaSetSystemAccessAccount );
39  INIT_LSAFUNC( LsaEnumeratePrivilegesOfAccount );
40  INIT_LSAFUNC( LsaAddPrivilegesToAccount );
41  INIT_LSAFUNC( LsaRemovePrivilegesFromAccount );
42  INIT_LSAFUNC( LsaGetQuotasForAccount );
43  INIT_LSAFUNC( LsaSetQuotasForAccount );
44  // Policy
45  INIT_LSAFUNC( LsaLookupPrivilegeValue );
46  INIT_LSAFUNC( LsaEnumeratePrivileges );
47  INIT_LSAFUNC( LsaDelete );
48  INIT_LSAFUNC( LsaQuerySecurityObject );
49  INIT_LSAFUNC( LsaSetSecurityObject );
50  //INIT_LSAFUNC( LsaChangePassword ); // R.I.P...
51  INIT_LSAFUNC( LsaClearAuditLog );
52  // Trusted Domain
53  INIT_LSAFUNC( LsaOpenTrustedDomain );
54  INIT_LSAFUNC( LsaCreateTrustedDomain );
55  INIT_LSAFUNC( LsaQueryInfoTrustedDomain );
56  INIT_LSAFUNC( LsaSetInformationTrustedDomain );
57  // Secret
58  INIT_LSAFUNC( LsaOpenSecret );
59  INIT_LSAFUNC( LsaCreateSecret );
60  INIT_LSAFUNC( LsaSetSecret );
61  INIT_LSAFUNC( LsaQuerySecret );
62  // Privilege Object
63  INIT_LSAFUNC( LsaLookupPrivilegeName );
64  INIT_LSAFUNC( LsaLookupPrivilegeDisplayName );
65  // New APIs for NT 4.0 (SUR release)
66  INIT_LSAFUNC( LsaGetUserName );
67  INIT_LSAFUNC( LsaGetRemoteUserName );
68 
69  if ( !_LsaOpenAccount
81  || !_LsaDelete
84  //|| !_LsaChangePassword // R.I.P
90  || !_LsaOpenSecret
92  || !_LsaSetSecret
93  || !_LsaQuerySecret
96  || !_LsaGetUserName
98  {
99  // One or more functions not found ...
100  if (!anyPtr) SetLastError( ERROR_MOD_NOT_FOUND ); // None
101  else SetLastError( ERROR_PROC_NOT_FOUND ); // Some
102  ok = false;
103  }
104  }
105  }
106  return ok;
107 }
108 
109 #undef INIT_LSAFUNC
110 #undef _INIT_FP_
111 
112 
113 //== Local (private) subroutines ----------------------------------------------
114 
115 static NTSTATUS __OpenOrCreateAccount(
116  LSA_HANDLE hPolicy, PSID AcctSid, ACCESS_MASK Accs, PLSA_HANDLE phAccount
117  )
118 {
119  // Open an account object. If it doesn't exist, create a new one.
120 
121  NTSTATUS Status = _LsaOpenAccount( hPolicy, AcctSid, Accs, phAccount );
122  if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
123  Status = _LsaCreateAccount( hPolicy, AcctSid, Accs, phAccount );
124 
125  return Status;
126 }
127 
128 //=============================================================================
129 // UmLsa addendum
130 //=============================================================================
131 
132 bool OpenLsaPolicy( CSTR Machine, ACCESS_MASK Access, PLSA_HANDLE phPolicy )
133 {
134  LSA_OBJECT_ATTRIBUTES ObjAttr;
135  PUNICODE_STRING puSys;
136  UString uName; // Handy indeed..
137 
138  // TODO: This doesn't work on Win11. Examine what's the matter..
139 
140  if (!Machine) puSys = NULL;
141  else puSys = uName = Machine; // Autoconvert to Unicode if necessary
142 
143  // Attempt to open the policy.
144 
145  ZeroMemory( &ObjAttr, sizeof(ObjAttr) );
146  NTSTATUS rc = LsaOpenPolicy( puSys, &ObjAttr, Access, phPolicy );
147 
148  bool ok = NT_SUCCESS( rc );
149  if (!ok) SetLastError( LsaNtStatusToWinError( rc ));
150  return ok;
151 }
152 
153 // LsaCloseEx returns NULL on success, else hLsa and GetLastError.
154 
155 LSA_HANDLE LsaCloseEx( LSA_HANDLE hLsa )
156 {
157  if (hLsa)
158  {
159  NTSTATUS rc = LsaClose( hLsa );
160  if (NT_SUCCESS( rc )) hLsa = NULL;
161  else SetLastError( LsaNtStatusToWinError( rc ));
162  }
163  return hLsa;
164 }
165 
166 // GetAdminGroupSid returns the SID of the BUILTIN\Administators group.
167 // @note Don't forget FreeSid.
168 
170 {
171  PSID adminGrp = NULL;
172  #if 1
173  SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
174 
175  if (!AllocateAndInitializeSid(
176  &Authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
177  0, 0, 0, 0, 0, 0, &adminGrp
178  )) adminGrp = NULL;
179 
180  #else
181  // Note: This necessitates mem_Free (e.g. FreeAccountSid), not FreeSid.
182  WELL_KNOWN_SID_TYPE wkSid = WinBuiltinAdministratorsSid;
183  DWORD cbSid = 0;
184  if (!CreateWellKnownSid( wkSid, NULL, NULL, &cbSid )
185  && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) // Mandatory error!
186  {
187  adminGrp = (PSID) mem_Alloc( cbSid );
188  if (adminGrp && !CreateWellKnownSid( wkSid, NULL, adminGrp, &cbSid ))
189  adminGrp = mem_Free( adminGrp );
190  }
191  #endif
192  return adminGrp;
193 }
194 
195 //==---------------------------------------------------------------------------
196 
197 bool GetAccountSid( CSTR Machine, CSTR Account, PSID* ppSid )
198 {
199  SID_NAME_USE peUse;
200  DWORD cbSid, ccDomain, err;
201  bool ok = false;
202 
203  if (!ppSid) SetLastError( ERROR_INVALID_PARAMETER );
204  else
205  {
206  cbSid = ccDomain = 0;
207  LookupAccountName( Machine, Account, NULL, &cbSid, NULL, &ccDomain, &peUse );
208  if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) // Mandatory error ;)
209  {
210  *ppSid = mem_Alloc( cbSid );
211  if (!*ppSid) err = ERROR_OUTOFMEMORY;
212  else
213  {
214  TCHAR szDomain[ 128 ]; // Local, to avoid a 2nd heap allocation call.
215  // Not interested in the domain here, but must give LookupAccountName
216  // a domain name buffer to avoid a second ERROR_INSUFFICIENT_BUFFER.
217  _ASSERTE( dimof(szDomain) >= ccDomain ); // Assert the max-length assumption
218  ccDomain = dimof(szDomain);
219 
220  ok = bool_cast( LookupAccountName(
221  Machine, Account, *ppSid, &cbSid, szDomain, &ccDomain, &peUse
222  ));
223  if (!ok) err = GetLastError();
224  }
225 
226  if (!ok)
227  {
228  *ppSid = mem_Free( *ppSid );
229  SetLastError( err );
230  }
231  }
232  }
233  return ok;
234 }
235 
236 PSID FreeAccountSid( PSID Sid )
237 {
238  return (PSID) mem_Free( Sid );
239 }
240 
242 {
243  // Get the SID of the user associated with the current thread.
244  // Build a fully qualified local username (limit lookup to this machine).
245 
246  TCHAR szLocalUser[ MAX_COMPUTERNAME_LENGTH + UNLEN + 1 ];
247  DWORD ccMachine = MAX_COMPUTERNAME_LENGTH + 1; // 16
248  DWORD ccUser = UNLEN + 1; // 257
249 
250  GetComputerName( szLocalUser, &ccMachine );
251  szLocalUser[ ccMachine ] = BSLASH;
252  GetUserName( &szLocalUser[ ccMachine+1 ], &ccUser );
253 
254  PSID userSid; // Get the SID
255  if (!GetAccountSid( NULL, szLocalUser, &userSid )) userSid = NULL;
256  return userSid;
257 }
258 
259 //==---------------------------------------------------------------------------
260 
261 bool GetLogonSid( HANDLE hToken, PSID *ppSid )
262 {
263  BOOL ok = false;
264  DWORD ix, cbGrp = 0;
265  PTOKEN_GROUPS ptGrp = NULL;
266 
267  //*ppSid = NULL;
268  GetTokenInformation( hToken, TokenGroups, NULL, 0, &cbGrp );
269  if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
270  {
271  ptGrp = (PTOKEN_GROUPS) mem_Alloc( cbGrp );
272  ok = (ptGrp != NULL);
273  if (ok) ok = GetTokenInformation(
274  hToken, TokenGroups, (PVOID) ptGrp, cbGrp, &cbGrp
275  );
276  if (ok)
277  {
278  for( ix=0; ix < ptGrp->GroupCount; ++ix )
279  // SE_GROUP_LOGON_ID is a two bit flag, so use the BITS_SET macro.
280  if (BITS_SET( SE_GROUP_LOGON_ID, ptGrp->Groups[ix].Attributes ))
281  {
282  DWORD cbSid = GetLengthSid( ptGrp->Groups[ix].Sid );
283  *ppSid = (PSID) mem_Alloc( cbSid );
284  CopySid( cbSid, *ppSid, ptGrp->Groups[ix].Sid );
285  break;
286  }
287  }
288  ptGrp = (PTOKEN_GROUPS) mem_Free( ptGrp );
289  }
290  return bool_cast( ok );
291 }
292 
293 PSID FreeLogonSid( PSID Sid )
294 {
295  return (PSID) mem_Free( Sid );
296 }
297 
298 //==---------------------------------------------------------------------------
299 
300 //PSECURITY_DESCRIPTOR GetObjectAbsSecurityDescriptor( HANDLE hObj, SECURITY_INFORMATION Type )
301 //{
302 // PSECURITY_DESCRIPTOR pRelDsc = NULL;
303 // PSECURITY_DESCRIPTOR pAbsDsc = NULL;
304 // DWORD cbData = 0;
305 //
306 // PSECURITY_DESCRIPTOR pAbsDsc;
307 // DWORD cbAbsDsc, cbDacl, cbSacl, cbOwn, cbPri;
308 // PSID psOwn, psPri;
309 // PACL pSacl;
310 //
311 // GetUserObjectSecurity( hObj, &Type, pRelDsc, cbData, &cbData );
312 // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
313 // {
314 // pRelDsc = (PSECURITY_DESCRIPTOR) mem_Alloc( cbData );
315 // if (pRelDsc && GetUserObjectSecurity( hObj, &Type, pRelDsc, cbData, &cbData ))
316 // {
317 // ok = MakeAbsoluteSD( pSecDsc, pAbsDsc, &cbAbsDsc,
318 // pDacl, &cbDacl, pSacl, &cbSacl, psOwn, &cbOwn, psPri, &cbPri
319 // );
320 // }
321 // }
322 //}
323 
324 // Allocate and initialize an absolute security descriptor.
325 
326 PISECURITY_DESCRIPTOR AllocAbsoluteSecDesc( size_t cbDesc )
327 {
328  if (!cbDesc) cbDesc = sizeof(SECURITY_DESCRIPTOR);
329  PISECURITY_DESCRIPTOR pAbsSec = (PISECURITY_DESCRIPTOR) mem_Alloc( cbDesc );
330  if (pAbsSec)
331  {
332  if (!InitializeSecurityDescriptor( pAbsSec, SECURITY_DESCRIPTOR_REVISION ))
333  pAbsSec = (PISECURITY_DESCRIPTOR) mem_Free( pAbsSec );
334  }
335  return pAbsSec;
336 }
337 
338 PISECURITY_DESCRIPTOR MakeAbsoluteSecDesc(
339  PSID Owner, PSID Group, PACL Sacl, PACL Dacl,
340  SECURITY_DESCRIPTOR_CONTROL Control
341  )
342 {
343  PISECURITY_DESCRIPTOR pSec = (PISECURITY_DESCRIPTOR) AllocAbsoluteSecDesc();
344  if (pSec)
345  {
346  if (Control) SetSecurityDescriptorControl( pSec, Control, Control );
347  if (Owner) SetSecurityDescriptorOwner( pSec, Owner, false );
348  if (Group) SetSecurityDescriptorGroup( pSec, Group, false );
349  if (Dacl) SetSecurityDescriptorDacl( pSec, true, Dacl, false );
350  if (Sacl) SetSecurityDescriptorSacl( pSec, true, Sacl, false );
351  }
352  return pSec;
353 }
354 
355 //==---------------------------------------------------------------------------
356 
357 PISECURITY_DESCRIPTOR_RELATIVE GetObjectSecDesc(
358  HANDLE hObj, SECURITY_INFORMATION Type, PDWORD cbDesc
359  )
360 {
361  PISECURITY_DESCRIPTOR_RELATIVE pSec = NULL;
362  DWORD cbData = 0;
363 
364  if (!GetUserObjectSecurity( hObj, &Type, NULL, 0, &cbData )
365  && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) // Mandatory error
366  {
367  pSec = (PISECURITY_DESCRIPTOR_RELATIVE) mem_Alloc( cbData );
368  if (pSec)
369  {
370  pSec->Revision = SECURITY_DESCRIPTOR_REVISION;
371 
372  if (!GetUserObjectSecurity( hObj, &Type, pSec, cbData, &cbData ))
373  pSec = (PISECURITY_DESCRIPTOR_RELATIVE) mem_Free( pSec );
374 
375  if (pSec && cbDesc) *cbDesc = cbData;
376  }
377  }
378  return pSec;
379 }
380 
381 PSECURITY_DESCRIPTOR FreeObjectSecDesc( PSECURITY_DESCRIPTOR pSecDesc )
382 {
383  PISECURITY_DESCRIPTOR piSec = (PISECURITY_DESCRIPTOR) pSecDesc;
384 
385  // Don't try to free an absolute descriptor, since we don't know where the
386  // Owner, Group, Dacl, and Sacl came from, ergo don't know how to dispose them.
387 
388  if (BITS_SET( SE_SELF_RELATIVE, piSec->Control ))
389  {
390  pSecDesc = (PSECURITY_DESCRIPTOR) mem_Free( pSecDesc );
391  }
392  else SetLastError( ERROR_INVALID_PARAMETER );
393 
394  return pSecDesc;
395 }
396 
397 //==---------------------------------------------------------------------------
398 
400  HANDLE hObj, // hObj must have READ_CONTROL (DACL) or ACCESS_SYSTEM_SECURITY (SACL).
401  SECURITY_INFORMATION Type, size_t cbExtra,
402  PSECURITY_DESCRIPTOR* ppSecDesc, PDWORD cbSecDesc
403  )
404 {
405  PACL pAcl = NULL;
406  PISECURITY_DESCRIPTOR_RELATIVE pDsc = NULL;
407  DWORD ix, cbData = 0;
408 
409  pDsc = GetObjectSecDesc( hObj, Type, &cbData );
410  if (pDsc)
411  {
412  if (ppSecDesc) *ppSecDesc = pDsc;
413  if (cbSecDesc) *cbSecDesc = cbData;
414 
415  BOOL haveAcl, defAcl;
416  PACL pSrcAcl = NULL;
417  BOOL (WINAPI *getAcl)(
418  PSECURITY_DESCRIPTOR pSD, LPBOOL pExist, PACL* pAcl, LPBOOL pDef
419  );
420  switch( Type )
421  {
422  case DACL_SECURITY_INFORMATION: getAcl = GetSecurityDescriptorDacl; break;
423  case SACL_SECURITY_INFORMATION: getAcl = GetSecurityDescriptorSacl; break;
424  default: getAcl = NULL;
425  }
426  if (getAcl && getAcl( pDsc, &haveAcl, &pSrcAcl, &defAcl ) && haveAcl)
427  {
428  ACL_SIZE_INFORMATION aclInfo = { 0,0,0 };
429  aclInfo.AclBytesInUse = sizeof(ACL); //??
430  cbData = sizeof(ACL_SIZE_INFORMATION);
431 
432  if (GetAclInformation( pSrcAcl, &aclInfo, cbData, AclSizeInformation ))
433  {
434  cbData = aclInfo.AclBytesInUse + aclInfo.AclBytesFree;
435  cbData += (DWORD) cbExtra;
436  pAcl = (PACL) mem_Alloc( cbData );
437  if (pAcl)
438  {
439  static const DWORD aclRev = ACL_REVISION;
440  static const DWORD atEnd = MAXDWORD;
441 
442  if (!InitializeAcl( pAcl, cbData, aclRev ))
443  pAcl = (PACL) mem_Free( pAcl ); // Failed: Return NULL.
444  else if (aclInfo.AceCount)
445  {
446  for( ix = 0; ix < aclInfo.AceCount; ix++ )
447  {
448  PACE_HEADER pAce;
449  if (GetAce( pSrcAcl, ix, (void**)&pAce ))
450  if (!AddAce( pAcl, aclRev, atEnd, pAce, pAce->AceSize ))
451  DPrint( DP_ERROR, _F("AddAce: %s\n"), SysErrorMsg() );
452  }
453  }
454  }
455  }
456  }
457  // If caller didn't want the sec.desc, then dispose it.
458  if (!ppSecDesc) pDsc = (PISECURITY_DESCRIPTOR_RELATIVE) mem_Free( pDsc );
459  }
460  return pAcl;
461 }
462 
463 PACL FreeObjectAcl( PACL pDacl )
464 {
465  return (PACL) mem_Free( pDacl );
466 }
467 
468 //==---------------------------------------------------------------------------
469 
471  LSA_HANDLE hPolicy, PSID AcctSid, ACCESS_MASK AccsType, bool Add
472  )
473 {
474  // This function changes system access on the account represented by the
475  // supplied SID. An example of such access is the SeLogonServiceRight.
476 
477  LSA_HANDLE hAccount;
478  ACCESS_MASK Access;
479  NTSTATUS Status;
480 
481  // Open the account object. If it doesn't exist, create a new one
482 
483  Status = __OpenOrCreateAccount( hPolicy,
484  AcctSid, ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW, &hAccount
485  );
486  if (NT_SUCCESS( Status ))
487  {
488  // Get current system access flags
489 
490  Status = _LsaGetSystemAccessAccount( hAccount, &Access );
491  if (NT_SUCCESS( Status ))
492  {
493  // Change the specified access to the account
494 
495  if (Add) Access |= AccsType; else Access &= ~AccsType;
496  Status = _LsaSetSystemAccessAccount( hAccount, Access );
497  }
498  LsaClose( hAccount );
499  }
500 
501  bool ok = NT_SUCCESS( Status );
502  if (!ok) SetLastError( LsaNtStatusToWinError( Status ));
503  return ok;
504 }
505 
506 
508  LSA_HANDLE hPolicy, PSID AcctSid, ACCESS_MASK* Access
509  )
510 {
511  LSA_HANDLE hAccount;
512  NTSTATUS Status;
513 
514  Status = _LsaOpenAccount( hPolicy, AcctSid, ACCOUNT_VIEW, &hAccount );
515  if (NT_SUCCESS( Status ))
516  {
517  Status = _LsaGetSystemAccessAccount( hAccount, Access );
518  LsaClose( hAccount );
519  }
520 
521  bool ok = NT_SUCCESS( Status );
522  if (!ok) SetLastError( LsaNtStatusToWinError( Status ));
523  return ok;
524 }
525 
526 //==---------------------------------------------------------------------------
527 
529  LSA_HANDLE hPolicy, PSID AcctSid, CSTR Privilege, bool Add
530  )
531 {
532  PRIVILEGE_SET ps;
533  LSA_HANDLE hAccount;
534  NTSTATUS Status;
535 
536  // Obtain the LUID of the supplied privilege.
537 
538  UString uPrivilege( Privilege ); // Convert if necessary
539  Status = _LsaLookupPrivilegeValue( hPolicy, uPrivilege, &ps.Privilege[0].Luid ); // ps..Luid
540  if (NT_SUCCESS( Status ))
541  {
542  // Open the account object. If it doesn't exist, create a new one.
543 
544  Status = __OpenOrCreateAccount(
545  hPolicy, AcctSid, ACCOUNT_ADJUST_PRIVILEGES, &hAccount
546  );
547  if (NT_SUCCESS( Status ))
548  {
549  // Setup the rest of PRIVILEGE_SET
550 
551  ps.Privilege[0].Attributes = 0;
552  ps.PrivilegeCount = 1;
553  ps.Control = 0;
554 
555  // Add or remove the privileges to the account
556 
557  if (Add) Status = _LsaAddPrivilegesToAccount( hAccount, &ps );
558  else Status = _LsaRemovePrivilegesFromAccount( hAccount, false, &ps );
559 
560  LsaClose( hAccount );
561  }
562  }
563 
564  bool ok = NT_SUCCESS( Status );
565  if (!ok) SetLastError( LsaNtStatusToWinError( Status ));
566  return ok;
567 }
568 
569 bool ULSA_AccountHasPrivilege( LSA_HANDLE hPolicy, PSID AcctSid, WCSTR Privilege ) // internal
570 {
571  ULONG ix, nRights;
572  PUNICODE_STRING puRights;
573  NTSTATUS Status = LsaEnumerateAccountRights( hPolicy, AcctSid, &puRights, &nRights );
574  if (NT_SUCCESS( Status ))
575  {
576  UString uRight;
577  Status = STATUS_PRIVILEGE_NOT_HELD; // Assume privilege absent
578  for( ix=0; ix < nRights; ++ix )
579  {
580  uRight = puRights[ix]; // Make sure it's NUL terminated
581  if (0 == wcscmp( (PCWSTR)uRight, Privilege ))
582  {
583  Status = STATUS_SUCCESS;
584  break;
585  }
586  }
587  LsaFreeMemory( puRights );
588  }
589  bool ok = NT_SUCCESS( Status );
590  if (!ok) SetLastError( LsaNtStatusToWinError( Status ));
591  return ok;
592 }
593 
594 bool AccountHasPrivilege( LSA_HANDLE hPolicy, PSID AcctSid, CSTR Privilege )
595 {
596  NTSTATUS Status;
597  LUID prvLuid;
598 
599  // Lookup the LUID to see if the privilege exists.
600 
601  UString uPrivilege( Privilege ); // Convert if necessary
602  Status = _LsaLookupPrivilegeValue( hPolicy, uPrivilege, &prvLuid );
603  bool ok = NT_SUCCESS( Status );
604 
605  if ( ok ) ok = ULSA_AccountHasPrivilege( hPolicy, AcctSid, (WSTR)uPrivilege );
606  else SetLastError( LsaNtStatusToWinError( Status ));
607 
608  return ok;
609 }
610 
611 // TODO: bool UserHasPrivilege( LSA_HANDLE hPolicy, PSID userSid, CSTR Privilege );
612 // ^^ Incl all effective rights from account and groups..
613 
614 bool UserHasPrivilege( LSA_HANDLE hPolicy, PSID userSid, CSTR Privilege )
615 {
616  bool haveIt = false;
617  //LSA_HANDLE hPolicy = NULL;
618  //if (OpenLsaPolicy( NULL, POLICY_ALL_ACCESS, &hPolicy ))
619  //{
620  DebugBreak(); // Not implemented yet..
621  // hPolicy = LsaCloseEx( hPolicy );
622  //}
623  return haveIt;
624 }
625 
626 /*
627 bool EnablePrivileges( HANDLE hToken, bool Enable, PTOKEN_PRIVILEGES* ppSave, ... )
628 {
629  static const UINT MAX_PRIVS = 24; // 24 privileges defined in Windows 2000
630  PTOKEN_PRIVILEGES newTp = AllocPrivileges( MAX_PRIVS, NULL );
631  PTOKEN_PRIVILEGES saveTp = NULL;
632 
633  DWORD Attr, rc, cbRtn, cbSave = 0;
634  LUID Luid;
635  CSTR pzPrvName;
636  va_list va;
637 
638  va_start( va, ppSave );
639  Attr = Enable ? SE_PRIVILEGE_ENABLED : 0;
640 
641  while( (pzPrvName = va_arg( va, CSTR )) != NULL )
642  {
643  if (LookupPrivilegeValue( NULL, pzPrvName, &Luid ))
644  {
645  UINT ix = newTp->PrivilegeCount;
646  newTp->Privileges[ ix ].Luid = Luid;
647  newTp->Privileges[ ix ].Attributes = Attr;
648 
649  if (++newTp->PrivilegeCount == MAX_PRIVS) break;
650  }
651  }
652  if (ppSave)
653  {
654  saveTp = AllocPrivileges( newTp->PrivilegeCount, &cbSave );
655  *ppSave = saveTp;
656  }
657 
658  bool ok = bool_cast(
659  AdjustTokenPrivileges( hToken, FALSE, newTp, cbSave, saveTp, &cbRtn )
660  );
661  rc = GetLastError();
662 
663  if (!ok && saveTp)
664  {
665  *ppSave = FreePrivileges( *ppSave );
666  }
667  FreePrivileges( newTp );
668  if (!ok) SetLastError( rc );
669  return ok;
670 }
671 
672 bool RestorePrivileges( HANDLE hTok, PTOKEN_PRIVILEGES pSaved, bool Dispose )
673 {
674  bool ok = bool_cast( AdjustTokenPrivileges( hTok, FALSE, pSaved, 0, NULL, NULL ));
675  DWORD rc = ok ? 0 : GetLastError(); //DPrint( DP_ERROR,_T("[RestorePrivilege] AdjustTokenPrivileges failed: %s\n"), SysErrorMsg() );
676  if (Dispose) FreePrivileges( pSaved );
677  if (!ok) SetLastError( rc );
678  return ok;
679 }
680 */
681 //==---------------------------------------------------------------------------
682 // SetThreadPrivilegeEx - Adds temp priv if not in user's account..
683 //==---------------------------------------------------------------------------
684 
685 #define HPRIVILEGE_VER 2
686 #if (HPRIVILEGE_VER == 1)
687 
688 struct PRIVILEGE_ITEM // (HPRIVILEGE) Privilege item for SetTokenPrivilegeEx
689 {
690  CSTR Name; // Privilege name.
691  bool held; // Privilege already held by caller's account.
692  bool added; // Privilege successfully added to caller's account.
693  bool enabled; // Privilege successfully enabled.
694  PSID userSid; // Caller's SID
695  bool imperSelf; // ImpersonateSelf successfully called.
696  PTOKEN_PRIVILEGES ptPriv; // Buffer for previous privilege state.
697 };
698 
700 {
701  PRIVILEGE_ITEM* ppi = NULL;
702 
704  InitLsaFunc(); // Local Security Authority
705 
706  PSID userSid = GetCurrentUserSid(); // User of current thread..
707  if (userSid)
708  {
709  LSA_HANDLE hPolicy = NULL;
710  if (OpenLsaPolicy( NULL, POLICY_ALL_ACCESS, &hPolicy ))
711  {
712  ppi = (PRIVILEGE_ITEM*) mem_Alloc( sizeof(PRIVILEGE_ITEM) );
713  ppi->userSid = userSid;
714  ppi->Name = mem_DupStr( Privilege );
715 
716  ppi->held = AccountHasPrivilege( hPolicy, userSid, Privilege );
717  if (!ppi->held) ppi->added = SetAccountPrivilege( hPolicy, userSid, Privilege, true );
718  if (AccountHasPrivilege( hPolicy, userSid, Privilege )) // Did it take effect?
719  {
720  ACCESS_MASK tokenAcc = TOKEN_QUERY| TOKEN_ADJUST_PRIVILEGES;
721  HANDLE hThread = GetCurrentThread();
722  HANDLE hToken = NULL;
723 
724  BOOL ok = OpenThreadToken( hThread, tokenAcc, true, &hToken );
725  DWORD err = ok ? 0 : GetLastError();
726  if (err == ERROR_NO_TOKEN || err == ERROR_CANT_OPEN_ANONYMOUS)
727  {
728  // Add impersonation token to PEB, or change impersonation level.
729  ppi->imperSelf = bool_cast( ImpersonateSelf( SecurityImpersonation ));
730  if (ppi->imperSelf) ok = OpenThreadToken( hThread, tokenAcc, true, &hToken );
731  err = ok ? 0 : GetLastError();
732  }
733  if (hToken)
734  {
735  ppi->enabled = EnablePrivilege( hToken, Privilege, true, &ppi->ptPriv );
736  CloseHandle( hToken ); // I don't need to keep it open.. Do I?
737  }
738  }
739  hPolicy = LsaCloseEx( hPolicy );
740  }
741  if (!ppi) FreeAccountSid( userSid );
742  }
743  return (HPRIVILEGE) ppi;
744 }
745 
747 {
748  if (hPrv)
749  {
750  PRIVILEGE_ITEM* ppi = (PRIVILEGE_ITEM*) hPrv;
751  if (ppi->enabled)
752  {
753  ACCESS_MASK tokenAcc = TOKEN_QUERY| TOKEN_ADJUST_PRIVILEGES;
754  HANDLE hThread = GetCurrentThread();
755  HANDLE hToken = NULL;
756  if (OpenThreadToken( hThread, tokenAcc, true, &hToken ))
757  {
758  if (ppi->ptPriv) RestorePrivileges( hToken, ppi->ptPriv, false );
759  CloseHandle( hToken );
760  }
761  }
762  if (ppi->imperSelf) RevertToSelf(); // Dispose the impersonation token (in PEB)
763  if (ppi->added)
764  {
765  LSA_HANDLE hPolicy = NULL;
766  if (OpenLsaPolicy( NULL, POLICY_ALL_ACCESS, &hPolicy ))
767  {
768  SetAccountPrivilege( hPolicy, ppi->userSid, ppi->Name, false );
769  LsaCloseEx( hPolicy );
770  }
771  }
772  ppi->Name = mem_FreeStr( ppi->Name );
773  ppi->ptPriv = FreePrivileges( ppi->ptPriv );
774  ppi->userSid = FreeAccountSid( ppi->userSid );
775  hPrv = (HPRIVILEGE) mem_Free( (PVOID) hPrv );
776  }
777  return hPrv;
778 }
779 
780 #elif (HPRIVILEGE_VER == 2)
781 
782 #pragma pack( push, 1 )
783 struct PRIVILEGE_ITEM // (HPRIVILEGE) Privilege item for SetTokenPrivilegeEx
784 {
785  HTOKENEX hToken; // Impersonation token.
786  PSID userSid; // Caller's SID
787  CSTR Name; // Privilege name.
788  bool held; // Privilege already held by caller's account.
789  bool added; // Privilege successfully added to caller's account.
790  bool enabled; // Privilege successfully enabled.
791  BYTE _rsv; // Dword align oldPrv, else AdjustTokenPrivileges fail.
792  TOKEN_PRIVILEGES oldPrv; // Buffer for previous privilege state.
793  //LUID_AND_ATTRIBUTES more[7]; // Future, for a total of 8 accessible via oldPrv.
794 };
795 #pragma pack( pop )
796 
798 {
799  PRIVILEGE_ITEM* ppi = (PRIVILEGE_ITEM*) hPriv;
800  return GetThreadExToken( ppi->hToken );
801 }
802 
804 {
805  PRIVILEGE_ITEM* ppi = NULL;
806 
808  InitLsaFunc(); // Local Security Authority
809 
810  PSID userSid = GetCurrentUserSid(); // User of current thread..
811  if ( userSid )
812  {
813  LSA_HANDLE hPolicy;
814  if (OpenLsaPolicy( NULL, POLICY_ALL_ACCESS, &hPolicy ))
815  {
816  ppi = (PRIVILEGE_ITEM*) mem_Alloc( sizeof(PRIVILEGE_ITEM) );
817  ppi->userSid = userSid;
818  ppi->Name = mem_DupStr( Privilege );
819 
820  // FIXME: This ought to check /effective user rights/, incl group rights...
821  bool ok = ppi->held = AccountHasPrivilege( hPolicy, userSid, Privilege );
822  if ( !ok )
823  {
824  ppi->added = SetAccountPrivilege( hPolicy, userSid, Privilege, true );
825  ok = AccountHasPrivilege( hPolicy, userSid, Privilege ); // Did it take effect?
826  }
827  if ( ok )
828  {
829  ACCESS_MASK tokenAcc = TOKEN_QUERY| TOKEN_ADJUST_PRIVILEGES;
830  HANDLE hThread = GetCurrentThread();
831 
832  ppi->hToken = OpenThreadTokenEx( hThread, tokenAcc );
833  if ( ppi->hToken )
834  {
835  ppi->oldPrv.PrivilegeCount = 1;
836  HANDLE hToken = GetThreadExToken( ppi->hToken );
837  ppi->enabled = EnablePrivilege(
838  hToken, Privilege, true, &ppi->oldPrv.Privileges[0]
839  );
840  }
841  }
842  hPolicy = LsaCloseEx( hPolicy );
843  }
844  if (!ppi) FreeAccountSid( userSid );
845  }
846  return (HPRIVILEGE) ppi;
847 }
848 
850 {
851  if (hPrv)
852  {
853  PRIVILEGE_ITEM* ppi = (PRIVILEGE_ITEM*) hPrv;
854  if (ppi->enabled)
855  {
856  HANDLE hToken = GetPrivilegeToken( hPrv );
857  bool ok = RestorePrivilege( hToken, &ppi->oldPrv );
858  }
859  ppi->hToken = CloseThreadTokenEx( ppi->hToken );
860  if (ppi->added)
861  {
862  LSA_HANDLE hPolicy;
863  if (OpenLsaPolicy( NULL, POLICY_ALL_ACCESS, &hPolicy ))
864  {
865  SetAccountPrivilege( hPolicy, ppi->userSid, ppi->Name, false );
866  LsaCloseEx( hPolicy );
867  }
868  }
869  ppi->Name = mem_FreeStr( ppi->Name );
870  ppi->userSid = FreeAccountSid( ppi->userSid );
871  hPrv = (HPRIVILEGE) mem_Free( (PVOID) hPrv );
872  }
873  return hPrv;
874 }
875 
876 #elif (HPRIVILEGE_VER == 3) // PENDING
877 
878 struct TPRIV_ITEM
879 {
880  LUID_AND_ATTRIBUTES oldPrv; // Buffer for previous privilege state.
881  CSTR Name; // Privilege name.
882  // Unused (for privileges) Attributes bits.
883  #define TPF_HELD 0x01000000 // Privilege already held by caller's account.
884  #define TPF_ADDED 0x02000000 // Privilege successfully added to caller's account.
885  #define TPF_ENABLED 0x04000000 // Privilege successfully enabled.
886  #define TPF_MASK 0x07000000
887 };
888 struct PRIVILEGE_ITEM // (HPRIVILEGE) Privilege item for SetTokenPrivilegesEx
889 {
890  HTOKENEX hToken; // First, so HPRIVILEGE can be cast to token HANDLE.
891  PSID userSid; // Caller's SID
892  UINT nrPriv; // Nr of privileges
893  TPRIV_ITEM Priv[1]; // Privilege items
894 };
895 
897 {
898  PRIVILEGE_ITEM* ppi = NULL;
899  return (HPRIVILEGE) ppi;
900 }
901 
902 HPRIVILEGE SetThreadPrivilegesEx( UINT NrPriv, CSTR* Privileges )
903 {
904  PRIVILEGE_ITEM* ppi = NULL;
905 
907  InitLsaFunc(); // Local Security Authority
908 
909  PSID userSid = GetCurrentUserSid(); // User of current thread..
910  if ( userSid )
911  {
912  LSA_HANDLE hPolicy;
913  if (OpenLsaPolicy( NULL, POLICY_ALL_ACCESS, &hPolicy ))
914  {
915  ppi = (PRIVILEGE_ITEM*) mem_Alloc(
916  sizeof(PRIVILEGE_ITEM) + (NrPriv-1) * sizeof(TPRIV_ITEM)
917  );
918  ppi->userSid = userSid;
919  ppi->nrPriv = NrPriv;
920  for( UINT ix = 0; ix < NrPriv; ++ix )
921  {
922  DPrint( DP_DEBUG, _F("%lu: %s\n"), ix, Privileges[ix] );
923 
924  ppi->Priv[ix].Name = mem_DupStr( Privileges[ix] );
925  LookupPrivilegeValue( NULL, Privileges[ix], &ppi->Priv[ix].oldPrv.Luid );
926 
928  //bool ok = ppi->held = AccountHasPrivilege( hPolicy, userSid, Privilege );
929  //if ( !ok )
930  //{
931  // ppi->added = SetAccountPrivilege( hPolicy, userSid, Privilege, true );
932  // ok = AccountHasPrivilege( hPolicy, userSid, Privilege ); // Did it take effect?
933  //}
934  //if ( ok )
935  //{
936  // ACCESS_MASK tokenAcc = TOKEN_QUERY| TOKEN_ADJUST_PRIVILEGES;
937  // HANDLE hThread = GetCurrentThread();
938 
939  // ppi->hToken = OpenThreadTokenEx( hThread, tokenAcc );
940  // if ( ppi->hToken )
941  // {
942  // ppi->oldPrv.PrivilegeCount = 1;
943  // HANDLE hToken = GetThreadExToken( ppi->hToken );
944  // ppi->enabled = EnablePrivilege(
945  // hToken, Privilege, true, &ppi->oldPrv.Privileges[0]
946  // );
947  // }
948  //}
949  }
950  hPolicy = LsaCloseEx( hPolicy );
951  }
952  if (!ppi) FreeAccountSid( userSid );
953  }
954  return NULL;
955 }
956 
957 HPRIVILEGE RestoreThreadPrivileges( HPRIVILEGE hPrv )
958 {
959  if (hPrv)
960  {
961  PRIVILEGE_ITEM* ppi = (PRIVILEGE_ITEM*) hPrv;
962  //if (ppi->enabled)
963  //{
964  // HANDLE hToken = GetPrivilegeToken( hPrv );
965  // bool ok = RestorePrivileges( hToken, &ppi->oldPrv, false );
966  //}
967  //ppi->hToken = CloseThreadTokenEx( ppi->hToken );
968  //if (ppi->added)
969  //{
970  // LSA_HANDLE hPolicy;
971  // if (OpenLsaPolicy( NULL, POLICY_ALL_ACCESS, &hPolicy ))
972  // {
973  // SetAccountPrivilege( hPolicy, ppi->userSid, ppi->Name, false );
974  // LsaCloseEx( hPolicy );
975  // }
976  //}
977  //ppi->Name = mem_FreeStr( ppi->Name );
978  ppi->userSid = FreeAccountSid( ppi->userSid );
979  hPrv = (HPRIVILEGE) mem_Free( (PVOID) hPrv );
980  }
981  return hPrv;
982 }
983 #endif
984 
985 //==---------------------------------------------------------------------------
986 #ifdef __cplusplus
987 #ifndef __GNUC__ // MinGW(64) doesn't have ADSiid.
988 //==---------------------------------------------------------------------------
989 
991 
992 // Since LSA seems unable to enumerate a list of local groups, we're forced
993 // to enlist the aid of Active Direcory Services to get the group list.
994 // Once we got it, we can use LSA to get further properties of each.
995 
996 #define SID_NAME_NONE SID_NAME_USE(0)
997 
999 : Domain( NULL ), Sid( NULL ), sidUse( SID_NAME_NONE )
1000 {
1001  InitializeListEntry( this );
1002  Name = newStr( name );
1003 }
1004 
1005 #ifndef _UNICODE
1006 GroupEntry::GroupEntry( WSTR name ) // Autoconverter
1007 : Domain( NULL ), Sid( NULL ), sidUse( SID_NAME_NONE )
1008 {
1009  CHAR sBuf[ 128 ];
1010 
1011  InitializeListEntry( this );
1012  if (!WideCharToMultiByte( CP_ACP, 0, name,-1, sBuf,dimof(sBuf), NULL, NULL ))
1013  {
1014  TRACE( DP_ERROR, _F("WideCharToMultiByte failed: %s. Name will be blank.\n"), SysErrorMsg() );
1015  sBuf[0] = 0;
1016  }
1017  Name = newStr( sBuf );
1018 }
1019 #endif
1020 
1022 {
1023  deleteStr( Name );
1024  deleteStr( Domain );
1025  mem_Free( Sid );
1026 }
1027 
1028 bool __stdcall GroupEntry::_find_Sid( PLIST_ENTRY Entry, PVOID Ctx ) // static
1029 {
1030  PGroupEntry pItem = (PGroupEntry) Entry;
1031  CSTR Machine = (CSTR) Ctx;
1032 
1033  SID_NAME_USE sidUse;
1034  DWORD cbSid, ccDom;
1035  BOOL ok;
1036 
1037  cbSid = ccDom = 0;
1038  ok = LookupAccountName( Machine, pItem->Name, NULL, &cbSid, NULL, &ccDom, &sidUse );
1039  if (!ok && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1040  {
1041  pItem->Sid = (PSID) mem_Alloc( cbSid );
1042  if (pItem->Sid)
1043  {
1044  pItem->Domain = new TCHAR[ ccDom+2 ]; // Comply w newStr
1045  if (!pItem->Domain) ccDom = 0;
1046 
1047  ok = LookupAccountName( Machine,
1048  pItem->Name, pItem->Sid, &cbSid, (TSTR)pItem->Domain, &ccDom,
1049  &pItem->sidUse // Win7: Why are they all SidTypeAlias ?
1050  );
1051  if (!ok) ok = (GetLastError() == ERROR_INSUFFICIENT_BUFFER); // Domain
1052  if (!ok || !IsValidSid( pItem->Sid ))
1053  {
1054  deleteStr( pItem->Domain ); // Null safe.
1055  pItem->Sid = (PSID) mem_Free( pItem->Sid );
1056  }
1057  }
1058  }
1059  return true; // Continue enumeration
1060 }
1061 
1062 //==---------------------------------------------------------------------------
1063 
1065 : DLinkList(), Machine(NULL)
1066 {}
1067 
1069 {
1070  Clear();
1071 }
1072 
1074 {
1075  RemoveAll( _del_Entry );
1076  Machine = deleteStr( Machine );
1077 }
1078 
1079 bool __stdcall GroupList::_del_Entry( PLIST_ENTRY Entry, PVOID Ctx ) // static
1080 {
1081  delete (PGroupEntry) Entry;
1082  return true;
1083 }
1084 
1085 UINT GroupList::GetFromADS( CSTR Machine ) // Link with: ActiveDS.lib and ADSiid.lib
1086 {
1087  IADsContainer* pCont;
1088  IADsGroup* pGrp;
1089  IEnumVARIANT* pEnum;
1090  IUnknown* pUnk;
1091  IDispatch* pDisp;
1092 
1093  WCHAR wzPath[ MAX_PATH ];
1094  ULONG nEnum;
1095  HRESULT hr;
1096  BSTR bstr;
1097  VARIANT vDisp;
1098 
1099  #define _OK_ SUCCEEDED // Unhide the forest from behind the trees ;)
1100 
1101  bool shellInited = ShellFuncInitialized();
1102  if (!shellInited) InitShellFunc();
1103 
1104  // The way this is done is a bit finicky, and not well documented.
1105  // I found the ancestor for this code through a Google search, and adapted.
1106  // There may be more efficient algorithms (Computer->GroupCollection?)...
1107  // PONDER: Can I come up with a neater GetFromADS implementation?
1108 
1109  VariantInit( &vDisp );
1110  Clear(); // Discard any previous list
1111  this->Machine = newStr( Machine );
1112 
1113  UString uMachine( Machine ); //<< Auto-convert to Unicode if we're in Ansi mode
1114  swprintf_s( wzPath, dimof(wzPath), L"WinNT://%s,computer", (PCWSTR)uMachine );
1115 
1116  hr = ADsGetObject( wzPath, IID_IADsContainer, (void**)&pCont );
1117  if (_OK_( hr ))
1118  {
1119  if (_OK_( pCont->get__NewEnum( &pUnk )))
1120  {
1121  hr = pUnk->QueryInterface( IID_IEnumVARIANT, (void**)&pEnum );
1122  pUnk->Release();
1123  if (_OK_( hr ))
1124  {
1125  //#1:hr = pEnum->Next( 1, &vDisp, &nEnum );
1126  //#1:while( SUCCEEDED( hr ) && (nEnum > 0) )
1127  while(_OK_( pEnum->Next( 1, &vDisp, &nEnum )) && (nEnum > 0))
1128  {
1129  pDisp = V_DISPATCH( &vDisp );
1130 
1131  // IADsContainer::put_Filter doesn't seem to work, so
1132  // this is by trial and error, querying an IID_IADsGroup :/
1133 
1134  hr = pDisp->QueryInterface( IID_IADsGroup, (void**)&pGrp );
1135  pDisp->Release();
1136  if (_OK_( hr )) // A group, since it has an IID_IADsGroup
1137  {
1138  if (_OK_( pGrp->get_Name( &bstr )))
1139  {
1140  Append( new GroupEntry( bstr ));
1141  SysFreeString( bstr );
1142  }
1143  hr = pGrp->Release();
1144  }
1145  VariantInit( &vDisp );
1146  //#1:hr = pEnum->Next( 1, &vDisp, &nEnum );
1147  }
1148  pEnum->Release();
1149  }
1150  }
1151  pCont->Release();
1152  }
1153  if (!shellInited) DoneShellFunc();
1154 
1156  return Count;
1157  #undef _OK_
1158 }
1159 
1161 #endif//ndef __GNUC__
1162 #endif//def __cplusplus
1163 //==---------------------------------------------------------------------------
1164 /* REFERENCE
1165 How To Manage User Privileges Programmatically in Windows NT
1166 
1167 In Windows NT, privileges are used to provide a means of access control that
1168 differs from discretionary access control. A system manager uses privileges to
1169 control which users/groups are able to manipulate various aspects of the system.
1170 An application may use privileges when it changes a system resource, such as the
1171 system time, or when it shuts down the system.
1172 
1173 The User Manager tool can be used to grant and revoke privileges from accounts.
1174 
1175 Windows NT 3.51 provides functionality which allows the developer to manage
1176 privileges programmatically. This functionality is made available through LSA
1177 (Local Security Authority).
1178 
1179 An example of an application that would benefit from LSA is a service install
1180 program. If the service is configured to run under a user account, it is necessary
1181 for that account to have the SeServiceLogonRight "logon as a service" privilege.
1182 This article discusses how to take advantage of LSA to grant and revoke privileges
1183 from users and groups.
1184 
1185 Managing user privileges can be achieved programmatically using these steps:
1186 
1187 1. Open the policy on the target machine with LsaOpenPolicy().
1188  To grant privileges, open the policy with POLICY_CREATE_ACCOUNT and
1189  POLICY_LOOKUP_NAMES access. To revoke privileges, open the policy with
1190  POLICY_LOOKUP_NAMES access.
1191 
1192 2. Obtain a SID (security identifier) representing the user/group of interest.
1193  The LookupAccountName() and LsaLookupNames() APIs can obtain a SID from an
1194  account name.
1195 
1196 3. Call LsaAddAccountRights() to grant privileges to the user(s)
1197  represented by the supplied SID.
1198 
1199 4. Call LsaRemoveAccountRights() to revoke privileges from the user(s)
1200  represented by the supplied SID.
1201 
1202 5. Close the policy with LsaClose().
1203 
1204 To successfully grant and revoke privileges, the caller needs to be an
1205 Administrator on the target system.
1206 
1207 The LSA API LsaEnumerateAccountRights() can be used to determine
1208 which privileges have been granted to an account.
1209 
1210 The LSA API LsaEnumerateAccountsWithUserRight() can be used to determine
1211 which accounts have been granted a specified privilege.
1212 
1213 Documentation and header files for these LSA APIs is provided in the
1214 Windows 32 SDK in the MSTOOLS\SECURITY directory.
1215 
1216 In the lastest versions of the Win32 SDK, the headers appear in the
1217 mstools\samples\win32\winnt\security\include directory and the documentation
1218 is in ....\security\lsasamp\lsaapi.hlp.
1219 
1220 NOTE: These LSA APIs are currently implemented as Unicode only.
1221 */
1222 //==---------------------------------------------------------------------------
1223 // EOF
bool enabled
Definition: UmLsa.cpp:790
unsigned long DWORD
Definition: Common.h:414
SID_NAME_USE sidUse
Definition: UmLsa.h:353
UINT Count
Definition: ListFunc.h:186
_LSAFN_EXTERN NTSTATUS _LsaGetSystemAccessAccount(IN LSA_HANDLE AccountHandle, OUT PULONG SystemAccess)
bool GetAccountSystemAccess(LSA_HANDLE hPolicy, PSID AcctSid, ACCESS_MASK *Access)
Definition: UmLsa.cpp:507
PTOKEN_PRIVILEGES FreePrivileges(PTOKEN_PRIVILEGES pPrv)
Definition: SecUtil.cpp:94
bool SetAccountSystemAccess(LSA_HANDLE hPolicy, PSID AcctSid, ACCESS_MASK AccsType, bool Add)
Definition: UmLsa.cpp:470
_LSAFN_EXTERN NTSTATUS _LsaQuerySecurityObject(IN LSA_HANDLE ObjectHandle, IN SECURITY_INFORMATION SecurityInformation, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor)
HTOKENEX CloseThreadTokenEx(HTOKENEX hToken)
Definition: SecUtil.cpp:288
bool AccountHasPrivilege(LSA_HANDLE hPolicy, PSID AcctSid, CSTR Privilege)
Definition: UmLsa.cpp:594
#define CSTR
Definition: Common.h:329
CSTR mem_FreeStr(CSTR Dup)
Definition: StrFunc.cpp:270
_LSAFN_EXTERN NTSTATUS _LsaSetSecret(IN LSA_HANDLE SecretHandle, OPTIN PLSA_UNICODE_STRING CurrentValue, OPTIN PLSA_UNICODE_STRING OldValue)
PSID GetAdminGroupSid()
Definition: UmLsa.cpp:169
bool ULSA_AccountHasPrivilege(LSA_HANDLE hPolicy, PSID AcctSid, WCSTR Privilege)
Definition: UmLsa.cpp:569
_LSAFN_EXTERN NTSTATUS _LsaQuerySecret(IN LSA_HANDLE SecretHandle, OPTOUT OPTIONAL PLSA_UNICODE_STRING *CurrentValue, OPTOUT PLARGE_INTEGER CurrentValueSetTime, OPTOUT PLSA_UNICODE_STRING *OldValue, OPTOUT PLARGE_INTEGER OldValueSetTime)
_LSAFN_EXTERN NTSTATUS _LsaSetSecurityObject(IN LSA_HANDLE ObjectHandle, IN SECURITY_INFORMATION SecurityInformation, IN PSECURITY_DESCRIPTOR SecurityDescriptor)
struct GroupEntry GroupEntry
Definition: UmLsa.h:368
_LSAFN_EXTERN NTSTATUS _LsaOpenAccount(IN LSA_HANDLE PolicyHandle, IN PSID AccountSid, IN ACCESS_MASK DesiredAccess, OUT PLSA_HANDLE AccountHandle)
HPRIVILEGE SetThreadPrivilegesEx(UINT NrPriv, CSTR *Privileges)
#define DP_DEBUG
Definition: Debug.h:85
bool UserHasPrivilege(LSA_HANDLE hPolicy, PSID userSid, CSTR Privilege)
Definition: UmLsa.cpp:614
_LSAFN_EXTERN NTSTATUS _LsaRemovePrivilegesFromAccount(IN LSA_HANDLE AccountHandle, IN BOOLEAN AllPrivileges, OPTIN PPRIVILEGE_SET Privileges)
void * mem_Alloc(size_t Bytes)
Definition: MemFunc.cpp:33
CSTR newStr(CSTR Src)
Definition: StrFunc.cpp:167
wchar_t * WSTR
Definition: Common.h:366
HANDLE GetThreadExToken(HTOKENEX hTok)
Definition: SecUtil.cpp:238
HPRIVILEGE SetThreadPrivilegeEx(CSTR Privilege)
Definition: UmLsa.cpp:803
PSID FreeAccountSid(PSID Sid)
Definition: UmLsa.cpp:236
bool ForEach(PDListFunc Action, void *UserData=NULL)
Definition: ListCls.cpp:317
#define TSTR
Definition: Common.h:328
_LSAFN_EXTERN NTSTATUS _LsaQueryInfoTrustedDomain(IN LSA_HANDLE TrustedDomainHandle, IN TRUSTED_INFORMATION_CLASS InformationClass, OUT PVOID *Buffer)
bool InitShellFunc(bool useOle=false, DWORD coFlag=COINIT_APARTMENTTHREADED)
Definition: ShellUtil.cpp:37
#define dimof(x)
Definition: Common.h:949
#define END_NAMESPACE(name)
Definition: Common.h:225
UINT GetFromADS(CSTR Machine)
Definition: UmLsa.cpp:1085
TOKEN_PRIVILEGES oldPrv
Definition: UmLsa.cpp:792
void __cdecl DPrint(int Level, CSTR Fmt,...)
Definition: Debug.cpp:134
_LSAFN_EXTERN NTSTATUS _LsaCreateAccount(IN LSA_HANDLE PolicyHandle, IN PSID AccountSid, IN ACCESS_MASK DesiredAccess, OUT PLSA_HANDLE AccountHandle)
#define TRACE(_lvl,...)
Definition: Debug.h:216
_LSAFN_EXTERN NTSTATUS _LsaEnumeratePrivilegesOfAccount(IN LSA_HANDLE AccountHandle, OUT PPRIVILEGE_SET *Privileges)
struct _LIST_ENTRY * PLIST_ENTRY
bool EnablePrivilege(HANDLE hToken, CSTR Privilege, bool Enable, OPTOUT PLUID_AND_ATTRIBUTES pSave)
HANDLE GetPrivilegeToken(HPRIVILEGE hPriv)
Definition: UmLsa.cpp:797
bool ShellFuncInitialized()
Definition: ShellUtil.cpp:24
HTOKENEX OpenThreadTokenEx(HANDLE hThread, ACCESS_MASK tokenAccess)
Definition: SecUtil.cpp:252
void Clear()
Definition: UmLsa.cpp:1073
const wchar_t * WCSTR
Definition: Common.h:367
bool InitLsaFunc()
Definition: UmLsa.cpp:19
static bool __stdcall _find_Sid(PLIST_ENTRY Entry, PVOID Ctx)
Definition: UmLsa.cpp:1028
PACL FreeObjectAcl(PACL pDacl)
Definition: UmLsa.cpp:463
_LSAFN_EXTERN NTSTATUS _LsaGetRemoteUserName(OPTIN PLSA_UNICODE_STRING SystemName, OUT PLSA_UNICODE_STRING *UserName, OPTOUT PLSA_UNICODE_STRING *DomainName)
BOOL(WINAPI *SysImgList::Shell_GetImageLists)(HIMAGELIST *pimlLarge
const LPCTSTR CCSTR
Definition: Common.h:335
bool SetAccountPrivilege(LSA_HANDLE hPolicy, PSID AcctSid, CSTR Privilege, bool Add)
Definition: UmLsa.cpp:528
PLIST_ENTRY Append(PLIST_ENTRY Entry)
Definition: ListCls.cpp:90
void * mem_Free(void *pBlk)
Definition: MemFunc.cpp:124
PSID userSid
Definition: UmLsa.cpp:786
_LSAFN_EXTERN NTSTATUS _LsaLookupPrivilegeName(IN LSA_HANDLE PolicyHandle, IN PLUID Value, OUT PLSA_UNICODE_STRING *Name)
_LSAFN_EXTERN NTSTATUS _LsaLookupPrivilegeValue(IN LSA_HANDLE PolicyHandle, IN PLSA_UNICODE_STRING Name, OUT PLUID Value)
Definition: DynArray.h:18
GroupEntry * PGroupEntry
Definition: UmLsa.h:370
_LSAFN_EXTERN NTSTATUS _LsaEnumerateAccounts(IN LSA_HANDLE PolicyHandle, INOUT PLSA_ENUMERATION_HANDLE EnumerationContext, OUT PVOID *Buffer, IN ULONG PreferedMaximumLength, OUT PULONG CountReturned)
#define _OK_
_LSAFN_EXTERN NTSTATUS _LsaSetQuotasForAccount(IN LSA_HANDLE AccountHandle, IN PQUOTA_LIMITS QuotaLimits)
_LSAFN_EXTERN NTSTATUS _LsaOpenTrustedDomain(IN LSA_HANDLE PolicyHandle, IN PSID TrustedDomainSid, IN ACCESS_MASK DesiredAccess, OUT PLSA_HANDLE TrustedDomainHandle)
CSTR SysErrorMsg(DWORD Err=0, TSTR Buf=NULL, UINT Length=0)
Definition: Debug.cpp:39
bool GetAccountSid(CSTR Machine, CSTR Account, PSID *ppSid)
Definition: UmLsa.cpp:197
_LSAFN_EXTERN NTSTATUS _LsaGetUserName(OUT PLSA_UNICODE_STRING *UserName, OPTOUT PLSA_UNICODE_STRING *DomainName)
_LSAFN_EXTERN NTSTATUS _LsaCreateTrustedDomain(IN LSA_HANDLE PolicyHandle, IN PLSA_TRUST_INFORMATION TrustedDomainInformation, IN ACCESS_MASK DesiredAccess, OUT PLSA_HANDLE TrustedDomainHandle)
#define ACCOUNT_ADJUST_SYSTEM_ACCESS
Definition: UmLsa.h:519
bool RestorePrivilege(HANDLE hToken, PTOKEN_PRIVILEGES pSaved)
See EnablePrivilege(()
Definition: SecUtil.cpp:162
bool __forceinline bool_cast(BOOL B52)
Definition: Common.h:767
#define DP_ERROR
Definition: Debug.h:82
#define BITS_SET(bits, x)
Definition: Common.h:1016
#define ACCOUNT_VIEW
Definition: UmLsa.h:516
void RemoveAll(PDListFunc ItemAction, void *UserData=NULL)
Definition: ListCls.cpp:241
Debug and error handling support.
LSA_HANDLE LsaCloseEx(LSA_HANDLE hLsa)
Definition: UmLsa.cpp:155
PACL GetObjectAcl(HANDLE hObj, SECURITY_INFORMATION Type, size_t cbExtra, PSECURITY_DESCRIPTOR *ppSecDesc, PDWORD cbSecDesc)
Definition: UmLsa.cpp:399
_LSAFN_EXTERN NTSTATUS _LsaClearAuditLog(IN LSA_HANDLE PolicyHandle)
HANDLE HTOKENEX
Definition: UtilFunc.h:440
HANDLE HPRIVILEGE
Definition: UmLsa.h:260
#define SID_NAME_NONE
Definition: UmLsa.cpp:996
_LSAFN_EXTERN NTSTATUS _LsaEnumeratePrivileges(IN LSA_HANDLE PolicyHandle, INOUT PLSA_ENUMERATION_HANDLE EnumerationContext, OUT PVOID *Buffer, IN ULONG PreferedMaximumLength, OUT PULONG CountReturned)
PSECURITY_DESCRIPTOR FreeObjectSecDesc(PSECURITY_DESCRIPTOR pSecDesc)
Definition: UmLsa.cpp:381
_LSAFN_EXTERN NTSTATUS _LsaLookupPrivilegeDisplayName(IN LSA_HANDLE PolicyHandle, IN PLSA_UNICODE_STRING Name, OUT PLSA_UNICODE_STRING *DisplayName, OUT PSHORT LanguageReturned)
HTOKENEX hToken
Definition: UmLsa.cpp:785
#define BEGIN_NAMESPACE(name)
Definition: Common.h:224
_LSAFN_EXTERN NTSTATUS _LsaOpenSecret(IN LSA_HANDLE PolicyHandle, IN PLSA_UNICODE_STRING SecretName, IN ACCESS_MASK DesiredAccess, OUT PLSA_HANDLE SecretHandle)
PSID FreeLogonSid(PSID Sid)
Definition: UmLsa.cpp:293
_LSAFN_EXTERN NTSTATUS _LsaSetInformationTrustedDomain(IN LSA_HANDLE TrustedDomainHandle, IN TRUSTED_INFORMATION_CLASS InformationClass, IN PVOID Buffer)
CSTR Machine
Definition: UmLsa.h:378
#define InitializeListEntry(E)
Definition: ListFunc.h:88
#define BSLASH
Definition: Common.h:1217
_LSAFN_EXTERN NTSTATUS _LsaDelete(IN LSA_HANDLE ObjectHandle)
#define _F(s)
Definition: Debug.h:49
void DoneShellFunc()
Definition: ShellUtil.cpp:64
_LSAFN_EXTERN NTSTATUS _LsaSetSystemAccessAccount(IN LSA_HANDLE AccountHandle, IN ULONG SystemAccess)
bool OpenLsaPolicy(CSTR Machine, ACCESS_MASK Access, PLSA_HANDLE phPolicy)
Definition: UmLsa.cpp:132
_LSAFN_EXTERN NTSTATUS _LsaCreateSecret(IN LSA_HANDLE PolicyHandle, IN PLSA_UNICODE_STRING SecretName, IN ACCESS_MASK DesiredAccess, OUT PLSA_HANDLE SecretHandle)
bool GetLogonSid(HANDLE hToken, PSID *ppSid)
Definition: UmLsa.cpp:261
bool RestorePrivileges(HANDLE hToken, PTOKEN_PRIVILEGES pSaved, bool Dispose)
Definition: SecUtil.cpp:219
#define NT_SUCCESS(Status)
Definition: Common.h:154
CSTR deleteStr(CSTR Dup)
Definition: StrFunc.cpp:191
#define ACCOUNT_ADJUST_PRIVILEGES
Definition: UmLsa.h:517
HPRIVILEGE RestoreThreadPrivilege(HPRIVILEGE hPrv)
Definition: UmLsa.cpp:849
PISECURITY_DESCRIPTOR MakeAbsoluteSecDesc(PSID Owner, PSID Group, PACL Sacl, PACL Dacl, SECURITY_DESCRIPTOR_CONTROL Control)
Definition: UmLsa.cpp:338
_LSAFN_EXTERN NTSTATUS _LsaGetQuotasForAccount(IN LSA_HANDLE AccountHandle, OUT PQUOTA_LIMITS QuotaLimits)
PISECURITY_DESCRIPTOR AllocAbsoluteSecDesc(size_t cbDesc)
Definition: UmLsa.cpp:326
PSID GetCurrentUserSid()
Definition: UmLsa.cpp:241
_LSAFN_EXTERN NTSTATUS _LsaAddPrivilegesToAccount(IN LSA_HANDLE AccountHandle, IN PPRIVILEGE_SET Privileges)
unsigned char BYTE
Definition: Common.h:412
GroupEntry(CSTR name)
Definition: UmLsa.cpp:998
#define mem_DupStr
Definition: StrFunc.h:141
PISECURITY_DESCRIPTOR_RELATIVE GetObjectSecDesc(HANDLE hObj, SECURITY_INFORMATION Type, PDWORD cbDesc)
Definition: UmLsa.cpp:357
unsigned long * PDWORD
Definition: Common.h:414