uLib  User mode C/C++ extended API library for Win32 programmers.
SecUtil.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - User mode library.
3 // Module: Security utility functions (Migrated from UtilFunc.cpp)
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 // Note: See also UmLsa.h/cpp for more advanced functions...
8 
9 #include <uLib/Common.h>
10 #include <uLib/UtilFunc.h>
11 #include <uLib/Debug.h>
12 #include <uLib/StrFunc.h>
13 
14 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15 // Authorization functions
16 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17 
18 bool InitializeSecDesc( PSECURITY_DESCRIPTOR pSecDesc, PACL AccsList )
19 {
20  if (!InitializeSecurityDescriptor( pSecDesc, SECURITY_DESCRIPTOR_REVISION ))
21  return false;
22  //PACL AccsList = NULL; // Null DACL grants full access to Everyone
23  return bool_cast( SetSecurityDescriptorDacl( pSecDesc, TRUE, AccsList, FALSE ));
24 }
25 
26 // EnableProcessPrivilege/s
27 
28 bool EnableProcessPrivilege( CSTR prvName, bool Enable )
29 {
30  HANDLE hToken;
31  DWORD rc;
32  bool ok = bool_cast(
33  OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken )
34  );
35  if (ok)
36  {
37  LUID_AND_ATTRIBUTES prev;
38  ok = EnablePrivilege( hToken, prvName, Enable, &prev );
39  rc = GetLastError();
40  CloseHandle( hToken );
41  if (!ok) SetLastError( rc );
42  }
43  return ok;
44 }
45 
46 bool EnableProcessPrivileges( bool Enable, CSTR szPriv, ... )
47 {
48  static const UINT MAX_PRIVS = 24; // 24 privileges defined in Windows 2000
49  PTOKEN_PRIVILEGES newTp = AllocPrivileges( MAX_PRIVS, NULL );
50 
51  HANDLE hToken, hProc = GetCurrentProcess();
52  DWORD rc, attr = Enable ? SE_PRIVILEGE_ENABLED : 0;
53  LUID luid;
54  va_list va;
55 
56  bool ok = bool_cast( OpenProcessToken( hProc, TOKEN_ADJUST_PRIVILEGES, &hToken ));
57  if (!ok) rc = GetLastError();
58  else
59  {
60  va_start( va, szPriv );
61  while( szPriv )
62  {
63  if (LookupPrivilegeValue( NULL, szPriv, &luid ))
64  {
65  UINT ix = newTp->PrivilegeCount;
66  newTp->Privileges[ ix ].Luid = luid;
67  newTp->Privileges[ ix ].Attributes = attr;
68 
69  if (++newTp->PrivilegeCount == MAX_PRIVS) break;
70  }
71  szPriv = va_arg( va, CSTR );
72  }
73  ok = bool_cast( AdjustTokenPrivileges( hToken, FALSE, newTp, 0, NULL, NULL ));
74  if (!ok) rc = GetLastError();
75  CloseHandle( hToken );
76  }
77 
78  FreePrivileges( newTp );
79  if (!ok) SetLastError( rc );
80  return ok;
81 }
82 
83 // Token privilege allocation helpers
84 
85 PTOKEN_PRIVILEGES AllocPrivileges( UINT Count, PDWORD pSize )
86 {
87  DWORD Size = sizeof(TOKEN_PRIVILEGES) + (Count-1)*sizeof(LUID_AND_ATTRIBUTES);
88  PTOKEN_PRIVILEGES pPrv = (PTOKEN_PRIVILEGES) mem_Alloc( Size );
89  if (pSize) *pSize = Size; // Return Size even if alloc failed to NULL.
90  pPrv->PrivilegeCount = Count;
91  return pPrv;
92 }
93 
94 PTOKEN_PRIVILEGES FreePrivileges( PTOKEN_PRIVILEGES pPrv )
95 {
96  return (PTOKEN_PRIVILEGES) mem_Free( pPrv );
97 }
98 
99 #if 0 // EnablePrivilege: Obsoleted version..
100 //bool EnablePrivilege( HANDLE hToken, CSTR prvName, bool Enable, PTOKEN_PRIVILEGES* ppPrev )
101 //{
102 // TOKEN_PRIVILEGES newTp, *oldTp = NULL;
103 // DWORD cbPrev = 0, cbRcv = 0, rc;
104 // bool ok = false;
105 //
106 // if (LookupPrivilegeValue( NULL, prvName, &newTp.Privileges[0].Luid ))
107 // {
108 // newTp.PrivilegeCount = 1;
109 // newTp.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
110 //
111 // if (ppPrev)
112 // {
113 // oldTp = AllocPrivileges( 1, &cbPrev );
114 // *ppPrev = oldTp; // NULL or newly allocated.
115 // }
116 // ok = bool_cast( AdjustTokenPrivileges( hToken, FALSE, &newTp, cbPrev, oldTp, &cbRcv ));
117 // rc = GetLastError();
118 // if (!ok)
119 // {
120 // TRACE( DP_DEBUG, _F("AdjustTokenPrivileges: %s\n"), SysErrorMsg( rc ));
121 // if (ppPrev) *ppPrev = FreePrivileges( *ppPrev );
122 // SetLastError( rc );
123 // }
124 // }
125 // return ok;
126 //}
127 #endif
128 
129 // EnablePrivilege - hToken must be opened with the following permissions:
130 //
131 // TOKEN_ADJUST_PRIVILEGES (to adjust the privilege)
132 // TOKEN_QUERY (to get the old privilege setting)
133 //
134 // This version uses preallocated TOKEN_PRIVILEGES array for old state..
135 // E.g: TOKEN_PRIVILEGES tp = { 1, { 0,0 }};
136 // bool prvOk = EnablePrivilege( hToken, SE_LOCK_MEMORY_NAME, true, &tp.Privileges[0] );
137 
138 bool EnablePrivilege( HANDLE hToken, CSTR Privilege, bool Enable, PLUID_AND_ATTRIBUTES pSave )
139 {
140  TOKEN_PRIVILEGES newTp, oldTp;
141  DWORD cbRcv = 0;
142 
143  BOOL ok = LookupPrivilegeValue( NULL, Privilege, &newTp.Privileges[0].Luid );
144  if ( ok )
145  {
146  newTp.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
147  newTp.PrivilegeCount = 1;
148 
149  ok = AdjustTokenPrivileges( hToken, FALSE, &newTp, sizeof(oldTp), &oldTp, &cbRcv );
150  TRACE_IF( !ok, DP_ERROR, _F("AdjustTokenPrivileges: %s\n"), SysErrorMsg() );
151  if (ok && pSave)
152  {
153  *pSave = oldTp.Privileges[ 0 ];
154  }
155  }
156  return bool_cast( ok );
157 }
158 
159 // RestorePrivilege
160 // Restore privileges from prevoius EnablePrivilege call.
161 
162 bool RestorePrivilege( HANDLE hToken, PTOKEN_PRIVILEGES pSaved )
163 {
164  _ASSERTE( !IsBadReadWritePtr( pSaved, sizeof(TOKEN_PRIVILEGES) ));
165  _ASSERTE( pSaved->PrivilegeCount == 1 );
166 
167  BOOL ok = AdjustTokenPrivileges( hToken, FALSE, pSaved, 0, NULL, NULL );
168  TRACE_IF( !ok, DP_ERROR, _F("AdjustTokenPrivileges: %s\n"), SysErrorMsg() );
169  return bool_cast( ok );
170 }
171 
172 // Enable multiple privileges.
173 
174 bool EnablePrivileges( HANDLE hToken, bool Enable, PTOKEN_PRIVILEGES* ppSave, ... )
175 {
176  static const UINT MAX_PRIVS = 24; // 24 privileges defined in Windows 2000
177  PTOKEN_PRIVILEGES newTp = AllocPrivileges( MAX_PRIVS, NULL );
178  PTOKEN_PRIVILEGES saveTp = NULL;
179 
180  DWORD Attr, rc, cbRtn, cbSave = 0;
181  LUID Luid;
182  CSTR pzPrvName;
183  va_list va;
184 
185  va_start( va, ppSave );
186  Attr = Enable ? SE_PRIVILEGE_ENABLED : 0;
187 
188  while( (pzPrvName = va_arg( va, CSTR )) != NULL )
189  {
190  if (LookupPrivilegeValue( NULL, pzPrvName, &Luid ))
191  {
192  UINT ix = newTp->PrivilegeCount;
193  newTp->Privileges[ ix ].Luid = Luid;
194  newTp->Privileges[ ix ].Attributes = Attr;
195 
196  if (++newTp->PrivilegeCount == MAX_PRIVS) break;
197  }
198  }
199  if (ppSave)
200  {
201  saveTp = AllocPrivileges( newTp->PrivilegeCount, &cbSave );
202  *ppSave = saveTp;
203  }
204 
205  bool ok = bool_cast(
206  AdjustTokenPrivileges( hToken, FALSE, newTp, cbSave, saveTp, &cbRtn )
207  );
208  rc = GetLastError();
209 
210  if (!ok && saveTp)
211  {
212  *ppSave = FreePrivileges( *ppSave );
213  }
214  FreePrivileges( newTp );
215  if (!ok) SetLastError( rc );
216  return ok;
217 }
218 
219 bool RestorePrivileges( HANDLE hTok, PTOKEN_PRIVILEGES pSaved, bool Dispose )
220 {
221  bool ok = bool_cast( AdjustTokenPrivileges( hTok, FALSE, pSaved, 0, NULL, NULL ));
222  DWORD rc = ok ? 0 : GetLastError(); //DPrint( DP_ERROR,_T("[RestorePrivilege] AdjustTokenPrivileges failed: %s\n"), SysErrorMsg() );
223  if (Dispose) FreePrivileges( pSaved );
224  if (!ok) SetLastError( rc );
225  return ok;
226 }
227 
228 //==---------------------------------------------------------------------------
229 // Under consideration: Always obtain a thread (impersonation) token.
230 //==---------------------------------------------------------------------------
231 
232 struct TOKENEX_ITEM // (HTOKENEX) Internal data for OpenThreadTokenEx
233 {
234  HANDLE hToken; // Thread token handle.
235  bool imperSelf; // Did we ImpersonateSelf() to get the token ?
236 };
237 
238 HANDLE GetThreadExToken( HTOKENEX hToken )
239 {
240  TOKENEX_ITEM* ptxi = (TOKENEX_ITEM*) hToken;
241  return ptxi->hToken;
242 }
243 
244 #if _DEBUG
245 static void _getTokenInt( HANDLE hTok, TOKEN_INFORMATION_CLASS Cls, PVOID Info, UINT Def )
246 {
247  DWORD cbRtn = 0; // If this is greater than TokenInformationLength, the function fails!
248  if (!GetTokenInformation( hTok, Cls, Info, sizeof(UINT), &cbRtn )) *(PUINT)Info = Def;
249 }
250  #endif
251 
252 HTOKENEX OpenThreadTokenEx( HANDLE hThread, ACCESS_MASK tokenAccess )
253 {
254  TOKENEX_ITEM* pti = (TOKENEX_ITEM*) mem_Alloc( sizeof(TOKENEX_ITEM) );
255 
256  tokenAccess |= TOKEN_IMPERSONATE;
257  bool openAsSelf = true; // Access check against the process security context.
258 
259  BOOL ok = OpenThreadToken( hThread, tokenAccess, openAsSelf, &pti->hToken );
260  DWORD error = ok ? NO_ERROR : GetLastError();
261  if (error == ERROR_NO_TOKEN || error == ERROR_CANT_OPEN_ANONYMOUS)
262  {
263  // This adds an impersonation token to the PEB, or changes impersonation level.
264 
265  pti->imperSelf = bool_cast( ImpersonateSelf( SecurityImpersonation ));
266  if (pti->imperSelf) ok = OpenThreadToken( hThread, tokenAccess, openAsSelf, &pti->hToken );
267  error = ok ? NO_ERROR : GetLastError();
268  }
269  TRACE_IF( !pti->hToken, DP_ERROR, _F("OpenThreadToken: %s\n"), SysErrorMsg() );
270  #if _DEBUG
271  if (pti->hToken)
272  {
273  TOKEN_TYPE typ; SECURITY_IMPERSONATION_LEVEL sil;
274  _getTokenInt( pti->hToken, TokenType, &typ, 0 );
275  _getTokenInt( pti->hToken, TokenImpersonationLevel, &sil, 4 );
276  _ASSERTE( typ == TokenImpersonation && sil == SecurityImpersonation );
277  }
278  #endif
279 
280  if ( !ok )
281  {
282  pti = (TOKENEX_ITEM*) mem_Free( pti );
283  SetLastError( error );
284  }
285  return (HTOKENEX) pti;
286 }
287 
289 {
290  TOKENEX_ITEM* pti = (TOKENEX_ITEM*) hToken;
291  bool ok = true;
292  if ( pti )
293  {
294  if (pti->imperSelf)
295  {
296  // RevertToSelf disposes the PEB impersonation token.
297  if (!RevertToSelf()) ok = false;
298  }
299  CloseHandleEx( pti->hToken );
300  pti = (TOKENEX_ITEM*) mem_Free( pti );
301  }
302  return HTOKENEX( ok ? pti : INVALID_HANDLE_VALUE );
303 }
304 
305 // EOF
HANDLE CloseHandleEx(HANDLE H)
Definition: KernelUtil.cpp:80
unsigned long DWORD
Definition: Common.h:414
bool EnableProcessPrivileges(bool Enable, CSTR szPriv,...)
Definition: SecUtil.cpp:46
PTOKEN_PRIVILEGES FreePrivileges(PTOKEN_PRIVILEGES pPrv)
Definition: SecUtil.cpp:94
HTOKENEX CloseThreadTokenEx(HTOKENEX hToken)
Definition: SecUtil.cpp:288
#define CSTR
Definition: Common.h:329
bool IsBadReadWritePtr(const PVOID address, UINT_PTR size)
Definition: KernelUtil.cpp:179
PTOKEN_PRIVILEGES AllocPrivileges(UINT Count, PDWORD pSize)
Definition: SecUtil.cpp:85
void * mem_Alloc(size_t Bytes)
Definition: MemFunc.cpp:33
HANDLE GetThreadExToken(HTOKENEX hToken)
Definition: SecUtil.cpp:238
bool InitializeSecDesc(PSECURITY_DESCRIPTOR pSecDesc, PACL AccsList)
Definition: SecUtil.cpp:18
bool EnableProcessPrivilege(CSTR prvName, bool Enable)
Definition: SecUtil.cpp:28
HTOKENEX OpenThreadTokenEx(HANDLE hThread, ACCESS_MASK tokenAccess)
Definition: SecUtil.cpp:252
bool EnablePrivilege(HANDLE hToken, CSTR Privilege, bool Enable, PLUID_AND_ATTRIBUTES pSave)
Definition: SecUtil.cpp:138
bool imperSelf
Definition: SecUtil.cpp:235
#define TRACE_IF(cond,...)
Definition: Debug.h:227
BOOL(WINAPI *SysImgList::Shell_GetImageLists)(HIMAGELIST *pimlLarge
void * mem_Free(void *pBlk)
Definition: MemFunc.cpp:124
CSTR SysErrorMsg(DWORD Err=0, TSTR Buf=NULL, UINT Length=0)
Definition: Debug.cpp:39
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
Debug and error handling support.
HANDLE HTOKENEX
Definition: UtilFunc.h:440
Common include; Added types, small "ubiquitous" utilities, et c.
#define _F(s)
Definition: Debug.h:49
bool RestorePrivileges(HANDLE hTok, PTOKEN_PRIVILEGES pSaved, bool Dispose)
Definition: SecUtil.cpp:219
HANDLE hToken
Definition: SecUtil.cpp:234
bool EnablePrivileges(HANDLE hToken, bool Enable, PTOKEN_PRIVILEGES *ppSave,...)
Definition: SecUtil.cpp:174
unsigned long * PDWORD
Definition: Common.h:414