1 /* 2 * dlls/rsaenh/handle.c 3 * Support code to manage HANDLE tables. 4 * 5 * Copyright 1998 Alexandre Julliard 6 * Copyright 2002-2004 Mike McCormack for CodeWeavers 7 * Copyright 2004 Michael Jung 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library 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 GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24 #define WIN32_NO_STATUS 25 #define WIN32_LEAN_AND_MEAN 26 27 //#include <string.h> 28 #include <stdarg.h> 29 30 #include <windef.h> 31 #include <winbase.h> 32 #include "handle.h" 33 34 #include <wine/debug.h> 35 36 WINE_DEFAULT_DEBUG_CHANNEL(handle); 37 38 #define HANDLE2INDEX(h) ((h)-1) 39 #define INDEX2HANDLE(i) ((i)+1) 40 41 /****************************************************************************** 42 * init_handle_table 43 * 44 * Initializes the HANDLETABLE structure pointed to by lpTable 45 * 46 * PARAMS 47 * lpTable [I] Pointer to the HANDLETABLE structure, which is to be initialized. 48 * 49 * NOTES 50 * You have to call destroy_handle_table when you don't need the table 51 * any more. 52 */ 53 void init_handle_table(struct handle_table *lpTable) 54 { 55 TRACE("(lpTable=%p)\n", lpTable); 56 57 lpTable->paEntries = NULL; 58 lpTable->iEntries = 0; 59 lpTable->iFirstFree = 0; 60 InitializeCriticalSection(&lpTable->mutex); 61 lpTable->mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": HANDLETABLE.mutex"); 62 } 63 64 /****************************************************************************** 65 * destroy_handle_table 66 * 67 * Destroys the handle table. 68 * 69 * PARAMS 70 * lpTable [I] Pointer to the handle table, which is to be destroyed. 71 */ 72 void destroy_handle_table(struct handle_table *lpTable) 73 { 74 TRACE("(lpTable=%p)\n", lpTable); 75 76 HeapFree(GetProcessHeap(), 0, lpTable->paEntries); 77 lpTable->mutex.DebugInfo->Spare[0] = 0; 78 DeleteCriticalSection(&lpTable->mutex); 79 } 80 81 /****************************************************************************** 82 * is_valid_handle 83 * 84 * Tests if handle is valid given the specified handle table 85 * 86 * PARAMS 87 * lpTable [I] Pointer to the handle table, with respect to which the handle's 88 * validness is tested. 89 * handle [I] The handle tested for validness. 90 * dwType [I] A magic value that identifies the referenced object's type. 91 * 92 * RETURNS 93 * TRUE, if handle is valid. 94 * FALSE, if handle is not valid. 95 */ 96 BOOL is_valid_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType) 97 { 98 unsigned int index = HANDLE2INDEX(handle); 99 BOOL ret = FALSE; 100 101 TRACE("(lpTable=%p, handle=%ld)\n", lpTable, handle); 102 103 EnterCriticalSection(&lpTable->mutex); 104 105 /* We don't use zero handle values */ 106 if (!handle) goto exit; 107 108 /* Check for index out of table bounds */ 109 if (index >= lpTable->iEntries) goto exit; 110 111 /* Check if this handle is currently allocated */ 112 if (!lpTable->paEntries[index].pObject) goto exit; 113 114 /* Check if this handle references an object of the correct type. */ 115 if (lpTable->paEntries[index].pObject->dwType != dwType) goto exit; 116 117 ret = TRUE; 118 exit: 119 LeaveCriticalSection(&lpTable->mutex); 120 return ret; 121 } 122 123 /****************************************************************************** 124 * grow_handle_table [Internal] 125 * 126 * Grows the number of entries in the given table by TABLE_SIZE_INCREMENT 127 * 128 * PARAMS 129 * lpTable [I] Pointer to the table, which is to be grown 130 * 131 * RETURNS 132 * TRUE, if successful 133 * FALSE, if not successful (out of memory on process heap) 134 * 135 * NOTES 136 * This is a support function for alloc_handle. Do not call! 137 */ 138 static BOOL grow_handle_table(struct handle_table *lpTable) 139 { 140 struct handle_table_entry *newEntries; 141 unsigned int i, newIEntries; 142 143 newIEntries = lpTable->iEntries + TABLE_SIZE_INCREMENT; 144 145 newEntries = HeapAlloc(GetProcessHeap(), 0, sizeof(struct handle_table_entry)*newIEntries); 146 if (!newEntries) 147 return FALSE; 148 149 if (lpTable->paEntries) 150 { 151 memcpy(newEntries, lpTable->paEntries, sizeof(struct handle_table_entry)*lpTable->iEntries); 152 HeapFree(GetProcessHeap(), 0, lpTable->paEntries); 153 } 154 155 for (i=lpTable->iEntries; i<newIEntries; i++) 156 { 157 newEntries[i].pObject = NULL; 158 newEntries[i].iNextFree = i+1; 159 } 160 161 lpTable->paEntries = newEntries; 162 lpTable->iEntries = newIEntries; 163 164 return TRUE; 165 } 166 167 /****************************************************************************** 168 * alloc_handle 169 * 170 * Allocates a new handle to the specified object in a given handle table. 171 * 172 * PARAMS 173 * lpTable [I] Pointer to the handle table, from which the new handle is 174 * allocated. 175 * lpObject [I] Pointer to the object, for which a handle shall be allocated. 176 * lpHandle [O] Pointer to a handle variable, into which the handle value will 177 * be stored. If not successful, this will be 178 * INVALID_HANDLE_VALUE 179 * RETURNS 180 * TRUE, if successful 181 * FALSE, if not successful (no free handle) 182 */ 183 static BOOL alloc_handle(struct handle_table *lpTable, OBJECTHDR *lpObject, HCRYPTKEY *lpHandle) 184 { 185 BOOL ret = FALSE; 186 187 TRACE("(lpTable=%p, lpObject=%p, lpHandle=%p)\n", lpTable, lpObject, lpHandle); 188 189 EnterCriticalSection(&lpTable->mutex); 190 if (lpTable->iFirstFree >= lpTable->iEntries) 191 if (!grow_handle_table(lpTable)) 192 { 193 *lpHandle = (HCRYPTKEY)INVALID_HANDLE_VALUE; 194 goto exit; 195 } 196 197 *lpHandle = INDEX2HANDLE(lpTable->iFirstFree); 198 199 lpTable->paEntries[lpTable->iFirstFree].pObject = lpObject; 200 lpTable->iFirstFree = lpTable->paEntries[lpTable->iFirstFree].iNextFree; 201 InterlockedIncrement(&lpObject->refcount); 202 203 ret = TRUE; 204 exit: 205 LeaveCriticalSection(&lpTable->mutex); 206 return ret; 207 } 208 209 /****************************************************************************** 210 * release_handle 211 * 212 * Releases resources occupied by the specified handle in the given table. 213 * The reference count of the handled object is decremented. If it becomes 214 * zero and if the 'destructor' function pointer member is non NULL, the 215 * destructor function will be called. Note that release_handle does not 216 * release resources other than the handle itself. If this is wanted, do it 217 * in the destructor function. 218 * 219 * PARAMS 220 * lpTable [I] Pointer to the handle table, from which a handle is to be 221 * released. 222 * handle [I] The handle, which is to be released 223 * dwType [I] Identifier for the type of the object, for which a handle is 224 * to be released. 225 * 226 * RETURNS 227 * TRUE, if successful 228 * FALSE, if not successful (invalid handle) 229 */ 230 BOOL release_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType) 231 { 232 unsigned int index = HANDLE2INDEX(handle); 233 OBJECTHDR *pObject; 234 BOOL ret = FALSE; 235 236 TRACE("(lpTable=%p, handle=%ld)\n", lpTable, handle); 237 238 EnterCriticalSection(&lpTable->mutex); 239 240 if (!is_valid_handle(lpTable, handle, dwType)) 241 goto exit; 242 243 pObject = lpTable->paEntries[index].pObject; 244 if (InterlockedDecrement(&pObject->refcount) == 0) 245 { 246 TRACE("destroying handle %ld\n", handle); 247 if (pObject->destructor) 248 pObject->destructor(pObject); 249 } 250 251 lpTable->paEntries[index].pObject = NULL; 252 lpTable->paEntries[index].iNextFree = lpTable->iFirstFree; 253 lpTable->iFirstFree = index; 254 255 ret = TRUE; 256 exit: 257 LeaveCriticalSection(&lpTable->mutex); 258 return ret; 259 } 260 261 /****************************************************************************** 262 * lookup_handle 263 * 264 * Returns the object identified by the handle in the given handle table 265 * 266 * PARAMS 267 * lpTable [I] Pointer to the handle table, in which the handle is looked up. 268 * handle [I] The handle, which is to be looked up 269 * lplpObject [O] Pointer to the variable, into which the pointer to the 270 * object looked up is copied. 271 * RETURNS 272 * TRUE, if successful 273 * FALSE, if not successful (invalid handle) 274 */ 275 BOOL lookup_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType, OBJECTHDR **lplpObject) 276 { 277 BOOL ret = FALSE; 278 279 TRACE("(lpTable=%p, handle=%ld, lplpObject=%p)\n", lpTable, handle, lplpObject); 280 281 EnterCriticalSection(&lpTable->mutex); 282 if (!is_valid_handle(lpTable, handle, dwType)) 283 { 284 *lplpObject = NULL; 285 goto exit; 286 } 287 *lplpObject = lpTable->paEntries[HANDLE2INDEX(handle)].pObject; 288 289 ret = TRUE; 290 exit: 291 LeaveCriticalSection(&lpTable->mutex); 292 return ret; 293 } 294 295 /****************************************************************************** 296 * copy_handle 297 * 298 * Copies a handle. Increments the reference count of the object referenced 299 * by the handle. 300 * 301 * PARAMS 302 * lpTable [I] Pointer to the handle table, which holds the handle to be copied. 303 * handle [I] The handle to be copied. 304 * copy [O] Pointer to a handle variable, where the copied handle is put. 305 * 306 * RETURNS 307 * TRUE, if successful 308 * FALSE, if not successful (invalid handle or out of memory) 309 */ 310 BOOL copy_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType, HCRYPTKEY *copy) 311 { 312 OBJECTHDR *pObject; 313 BOOL ret; 314 315 TRACE("(lpTable=%p, handle=%ld, copy=%p)\n", lpTable, handle, copy); 316 317 EnterCriticalSection(&lpTable->mutex); 318 if (!lookup_handle(lpTable, handle, dwType, &pObject)) 319 { 320 *copy = (HCRYPTKEY)INVALID_HANDLE_VALUE; 321 LeaveCriticalSection(&lpTable->mutex); 322 return FALSE; 323 } 324 325 ret = alloc_handle(lpTable, pObject, copy); 326 LeaveCriticalSection(&lpTable->mutex); 327 return ret; 328 } 329 330 /****************************************************************************** 331 * new_object 332 * 333 * Allocates a new object of size cbSize on the current process's heap. 334 * Initializes the object header using the destructor and dwType params. 335 * Allocates a handle to the object in the handle table pointed to by lpTable. 336 * Returns a pointer to the created object in ppObject. 337 * Returns a handle to the created object. 338 * 339 * PARAMS 340 * lpTable [I] Pointer to the handle table, from which a handle is to be 341 * allocated. 342 * cbSize [I] Size of the object to be allocated in bytes. 343 * dwType [I] Object type; will be copied to the object header. 344 * destructor [I] Function pointer to a destructor function. Will be called 345 * once the object's reference count gets zero. 346 * ppObject [O] Pointer to a pointer variable, where a pointer to the newly 347 * created object will be stored. You may set this to NULL. 348 * 349 * RETURNS 350 * INVALID_HANDLE_VALUE, if something went wrong. 351 * a handle to the new object, if successful. 352 */ 353 HCRYPTKEY new_object(struct handle_table *lpTable, size_t cbSize, DWORD dwType, DESTRUCTOR destructor, 354 OBJECTHDR **ppObject) 355 { 356 OBJECTHDR *pObject; 357 HCRYPTKEY hObject; 358 359 if (ppObject) 360 *ppObject = NULL; 361 362 pObject = HeapAlloc(GetProcessHeap(), 0, cbSize); 363 if (!pObject) 364 return (HCRYPTKEY)INVALID_HANDLE_VALUE; 365 366 pObject->dwType = dwType; 367 pObject->refcount = 0; 368 pObject->destructor = destructor; 369 370 if (!alloc_handle(lpTable, pObject, &hObject)) 371 HeapFree(GetProcessHeap(), 0, pObject); 372 else 373 if (ppObject) 374 *ppObject = pObject; 375 376 return hObject; 377 } 378