1 /* 2 * PROJECT: ReactOS Kernel 3 * COPYRIGHT: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ex/atom.c 5 * PURPOSE: Executive Atom Functions 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Gunnar Dalsnes 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS ****************************************************************/ 17 18 /* 19 * FIXME: this is WRONG! The global atom table should live in the WinSta struct 20 * and accessed through a win32k callout (received in PsEstablishWin32Callouts) 21 * NOTE: There is a session/win32k global atom table also, but its private to 22 * win32k. Its used for RegisterWindowMessage() and for window classes. 23 * -Gunnar 24 */ 25 PRTL_ATOM_TABLE GlobalAtomTable; 26 27 /* PRIVATE FUNCTIONS *********************************************************/ 28 29 /*++ 30 * @name ExpGetGlobalAtomTable 31 * 32 * Gets pointer to a global atom table, creates it if not already created 33 * 34 * @return Pointer to the RTL_ATOM_TABLE, or NULL if it's impossible 35 * to create atom table 36 * 37 * @remarks Internal function 38 * 39 *--*/ 40 PRTL_ATOM_TABLE 41 NTAPI 42 ExpGetGlobalAtomTable(VOID) 43 { 44 NTSTATUS Status; 45 46 /* Return it if we have one */ 47 if (GlobalAtomTable) return GlobalAtomTable; 48 49 /* Create it */ 50 Status = RtlCreateAtomTable(37, &GlobalAtomTable); 51 52 /* If we couldn't create it, return NULL */ 53 if (!NT_SUCCESS(Status)) return NULL; 54 55 /* Return the newly created one */ 56 return GlobalAtomTable; 57 } 58 59 /* FUNCTIONS ****************************************************************/ 60 61 /*++ 62 * @name NtAddAtom 63 * @implemented 64 * 65 * Function NtAddAtom creates new Atom in Global Atom Table. If Atom 66 * with the same name already exist, internal Atom counter is incremented. 67 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtAddAtom.html 68 * 69 * @param AtomName 70 * Atom name in Unicode 71 * 72 * @param AtomNameLength 73 * Length of the atom name 74 * 75 * @param Atom 76 * Pointer to RTL_ATOM 77 * 78 * @return STATUS_SUCCESS in case of success, proper error code 79 * otherwise. 80 * 81 * @remarks None 82 * 83 *--*/ 84 NTSTATUS 85 NTAPI 86 NtAddAtom(IN PWSTR AtomName, 87 IN ULONG AtomNameLength, 88 OUT PRTL_ATOM Atom) 89 { 90 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); 91 NTSTATUS Status; 92 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 93 LPWSTR CapturedName; 94 ULONG CapturedSize; 95 RTL_ATOM SafeAtom; 96 PAGED_CODE(); 97 98 /* Check for the table */ 99 if (AtomTable == NULL) return STATUS_ACCESS_DENIED; 100 101 /* Check for valid name */ 102 if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR))) 103 { 104 /* Fail */ 105 DPRINT1("Atom name too long\n"); 106 return STATUS_INVALID_PARAMETER; 107 } 108 109 /* Check if we're called from user-mode or kernel-mode */ 110 if (PreviousMode == KernelMode) 111 { 112 /* Re-use the given name if kernel mode */ 113 CapturedName = AtomName; 114 } 115 else 116 { 117 /* Check if we have a name */ 118 if (AtomName) 119 { 120 /* Allocate an aligned buffer + the null char */ 121 CapturedSize = ((AtomNameLength + sizeof(WCHAR)) & 122 ~(sizeof(WCHAR) -1)); 123 CapturedName = ExAllocatePoolWithTag(PagedPool, 124 CapturedSize, 125 TAG_ATOM); 126 127 if (!CapturedName) 128 { 129 /* Fail the call */ 130 return STATUS_INSUFFICIENT_RESOURCES; 131 } 132 133 /* Enter SEH */ 134 _SEH2_TRY 135 { 136 /* Probe the atom */ 137 ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR)); 138 139 /* Copy the name and null-terminate it */ 140 RtlCopyMemory(CapturedName, AtomName, AtomNameLength); 141 CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL; 142 143 /* Probe the atom too */ 144 if (Atom) ProbeForWriteUshort(Atom); 145 } 146 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 147 { 148 /* Return the exception code */ 149 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 150 } 151 _SEH2_END; 152 } 153 else 154 { 155 /* No name */ 156 CapturedName = NULL; 157 } 158 } 159 160 /* Call the runtime function */ 161 Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom); 162 if (NT_SUCCESS(Status) && (Atom)) 163 { 164 /* Success and caller wants the atom back.. .enter SEH */ 165 _SEH2_TRY 166 { 167 /* Return the atom */ 168 *Atom = SafeAtom; 169 } 170 _SEH2_EXCEPT(ExSystemExceptionFilter()) 171 { 172 /* Get the exception code */ 173 Status = _SEH2_GetExceptionCode(); 174 } 175 _SEH2_END; 176 } 177 178 /* If we captured anything, free it */ 179 if ((CapturedName != NULL) && (CapturedName != AtomName)) 180 ExFreePoolWithTag(CapturedName, TAG_ATOM); 181 182 /* Return to caller */ 183 return Status; 184 } 185 186 /*++ 187 * @name NtDeleteAtom 188 * @implemented 189 * 190 * Removes Atom from Global Atom Table. If Atom's reference counter 191 * is greater then 1, function decrements this counter, but Atom 192 * stayed in Global Atom Table. 193 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtDeleteAtom.html 194 * 195 * @param Atom 196 * Atom identifier 197 * 198 * @return STATUS_SUCCESS in case of success, proper error code 199 * otherwise. 200 * 201 * @remarks None 202 * 203 *--*/ 204 NTSTATUS 205 NTAPI 206 NtDeleteAtom(IN RTL_ATOM Atom) 207 { 208 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); 209 PAGED_CODE(); 210 211 /* Check for valid table */ 212 if (AtomTable == NULL) return STATUS_ACCESS_DENIED; 213 214 /* Call worker function */ 215 return RtlDeleteAtomFromAtomTable(AtomTable, Atom); 216 } 217 218 /*++ 219 * @name NtFindAtom 220 * @implemented 221 * 222 * Retrieves existing Atom's identifier without incrementing Atom's 223 * internal counter 224 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtFindAtom.html 225 * 226 * @param AtomName 227 * Atom name in Unicode 228 * 229 * @param AtomNameLength 230 * Length of the atom name 231 * 232 * @param Atom 233 * Pointer to RTL_ATOM 234 * 235 * @return STATUS_SUCCESS in case of success, proper error code 236 * otherwise. 237 * 238 * @remarks None 239 * 240 *--*/ 241 NTSTATUS 242 NTAPI 243 NtFindAtom(IN PWSTR AtomName, 244 IN ULONG AtomNameLength, 245 OUT PRTL_ATOM Atom) 246 { 247 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); 248 NTSTATUS Status; 249 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 250 _SEH2_VOLATILE LPWSTR CapturedName; 251 ULONG CapturedSize; 252 RTL_ATOM SafeAtom; 253 PAGED_CODE(); 254 255 /* Check for the table */ 256 if (AtomTable == NULL) return STATUS_ACCESS_DENIED; 257 258 /* Check for valid name */ 259 if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR))) 260 { 261 /* Fail */ 262 DPRINT1("Atom name too long\n"); 263 return STATUS_INVALID_PARAMETER; 264 } 265 266 /* Re-use the given name if kernel mode or no atom name */ 267 CapturedName = AtomName; 268 269 /* Check if we're called from user-mode*/ 270 if (PreviousMode != KernelMode) 271 { 272 /* Enter SEH */ 273 _SEH2_TRY 274 { 275 /* Check if we have a name */ 276 if (AtomName) 277 { 278 /* Probe the atom */ 279 ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR)); 280 281 /* Allocate an aligned buffer + the null char */ 282 CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~ 283 (sizeof(WCHAR) -1)); 284 CapturedName = ExAllocatePoolWithQuotaTag(PagedPool, 285 CapturedSize, 286 TAG_ATOM); 287 /* Copy the name and null-terminate it */ 288 RtlCopyMemory(CapturedName, AtomName, AtomNameLength); 289 CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL; 290 291 /* Probe the atom too */ 292 if (Atom) ProbeForWriteUshort(Atom); 293 } 294 } 295 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 296 { 297 if (CapturedName != AtomName) 298 { 299 ExFreePoolWithTag(CapturedName, TAG_ATOM); 300 } 301 302 /* Return the exception code */ 303 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 304 } 305 _SEH2_END; 306 } 307 308 /* Call the runtime function */ 309 Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom); 310 if (NT_SUCCESS(Status) && (Atom)) 311 { 312 /* Success and caller wants the atom back... enter SEH */ 313 _SEH2_TRY 314 { 315 /* Return the atom */ 316 *Atom = SafeAtom; 317 } 318 _SEH2_EXCEPT(ExSystemExceptionFilter()) 319 { 320 Status = _SEH2_GetExceptionCode(); 321 } 322 _SEH2_END; 323 } 324 325 /* If we captured anything, free it */ 326 if ((CapturedName) && (CapturedName != AtomName)) 327 ExFreePoolWithTag(CapturedName, TAG_ATOM); 328 329 /* Return to caller */ 330 return Status; 331 } 332 333 /*++ 334 * @name NtQueryInformationAtom 335 * @implemented 336 * 337 * Gets single Atom properties or reads Global Atom Table 338 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Atoms/NtQueryInformationAtom.html 339 * 340 * @param Atom 341 * Atom to query. If AtomInformationClass parameter is 342 * AtomTableInformation, Atom parameter is not used. 343 * 344 * @param AtomInformationClass 345 * See ATOM_INFORMATION_CLASS enumeration type for details 346 * 347 * @param AtomInformation 348 * Result of call - pointer to user's allocated buffer for data 349 * 350 * @param AtomInformationLength 351 * Size of AtomInformation buffer, in bytes 352 * 353 * @param ReturnLength 354 * Pointer to ULONG value containing required AtomInformation 355 * buffer size 356 * 357 * @return STATUS_SUCCESS in case of success, proper error code 358 * otherwise. 359 * 360 * @remarks None 361 * 362 *--*/ 363 NTSTATUS 364 NTAPI 365 NtQueryInformationAtom(RTL_ATOM Atom, 366 ATOM_INFORMATION_CLASS AtomInformationClass, 367 PVOID AtomInformation, 368 ULONG AtomInformationLength, 369 PULONG ReturnLength) 370 { 371 PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); 372 PATOM_BASIC_INFORMATION BasicInformation = AtomInformation; 373 PATOM_TABLE_INFORMATION TableInformation = AtomInformation; 374 NTSTATUS Status = STATUS_SUCCESS; 375 ULONG Flags, UsageCount, NameLength, RequiredLength = 0; 376 KPROCESSOR_MODE PreviousMode; 377 378 PAGED_CODE(); 379 380 /* Check for valid table */ 381 if (AtomTable == NULL) return STATUS_ACCESS_DENIED; 382 383 PreviousMode = ExGetPreviousMode(); 384 385 _SEH2_TRY 386 { 387 /* Probe the parameters */ 388 if (PreviousMode != KernelMode) 389 { 390 ProbeForWrite(AtomInformation, 391 AtomInformationLength, 392 sizeof(ULONG)); 393 394 if (ReturnLength != NULL) 395 { 396 ProbeForWriteUlong(ReturnLength); 397 } 398 } 399 400 /* Choose class */ 401 switch (AtomInformationClass) 402 { 403 /* Caller requested info about an atom */ 404 case AtomBasicInformation: 405 406 /* Size check */ 407 RequiredLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name); 408 if (RequiredLength > AtomInformationLength) 409 { 410 /* Fail */ 411 DPRINT1("Buffer too small\n"); 412 Status = STATUS_INFO_LENGTH_MISMATCH; 413 _SEH2_LEAVE; 414 } 415 416 /* Prepare query */ 417 UsageCount = 0; 418 NameLength = AtomInformationLength - RequiredLength; 419 BasicInformation->Name[0] = UNICODE_NULL; 420 421 /* Query the data */ 422 Status = RtlQueryAtomInAtomTable(AtomTable, 423 Atom, 424 &UsageCount, 425 &Flags, 426 BasicInformation->Name, 427 &NameLength); 428 if (NT_SUCCESS(Status)) 429 { 430 /* Return data */ 431 BasicInformation->UsageCount = (USHORT)UsageCount; 432 BasicInformation->Flags = (USHORT)Flags; 433 BasicInformation->NameLength = (USHORT)NameLength; 434 RequiredLength += NameLength + sizeof(WCHAR); 435 } 436 break; 437 438 /* Caller requested info about an Atom Table */ 439 case AtomTableInformation: 440 441 /* Size check */ 442 RequiredLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms); 443 if (RequiredLength > AtomInformationLength) 444 { 445 /* Fail */ 446 DPRINT1("Buffer too small\n"); 447 Status = STATUS_INFO_LENGTH_MISMATCH; 448 _SEH2_LEAVE; 449 } 450 451 /* Query the data */ 452 Status = RtlQueryAtomListInAtomTable(AtomTable, 453 (AtomInformationLength - RequiredLength) / 454 sizeof(RTL_ATOM), 455 &TableInformation->NumberOfAtoms, 456 TableInformation->Atoms); 457 if (NT_SUCCESS(Status)) 458 { 459 /* Update the return length */ 460 RequiredLength += TableInformation->NumberOfAtoms * sizeof(RTL_ATOM); 461 } 462 break; 463 464 /* Caller was on crack */ 465 default: 466 467 /* Unrecognized class */ 468 Status = STATUS_INVALID_INFO_CLASS; 469 break; 470 } 471 472 /* Return the required size */ 473 if (ReturnLength != NULL) 474 { 475 *ReturnLength = RequiredLength; 476 } 477 } 478 _SEH2_EXCEPT(ExSystemExceptionFilter()) 479 { 480 Status = _SEH2_GetExceptionCode(); 481 } 482 _SEH2_END; 483 484 /* Return to caller */ 485 return Status; 486 } 487 488 /* EOF */ 489