Fixed compilation bug
[reactos.git] / reactos / ntoskrnl / ps / create.c
1 /* $Id: create.c,v 1.10 2000/02/14 14:13:33 dwelch Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/thread.c
6 * PURPOSE: Thread managment
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * REVISION HISTORY:
9 * 23/06/98: Created
10 * 12/10/99: Phillip Susi: Thread priorities, and APC work
11 */
12
13 /*
14 * NOTE:
15 *
16 * All of the routines that manipulate the thread queue synchronize on
17 * a single spinlock
18 *
19 */
20
21 /* INCLUDES ****************************************************************/
22
23 #include <ddk/ntddk.h>
24 #include <internal/ke.h>
25 #include <internal/ob.h>
26 #include <string.h>
27 #include <internal/string.h>
28 #include <internal/hal.h>
29 #include <internal/ps.h>
30 #include <internal/ob.h>
31
32 #define NDEBUG
33 #include <internal/debug.h>
34
35 /* GLOBAL *******************************************************************/
36
37 static ULONG PiNextThreadUniqueId = 0;
38
39 extern KSPIN_LOCK PiThreadListLock;
40 extern ULONG PiNrThreads;
41
42 extern LIST_ENTRY PiThreadListHead;
43
44 /* FUNCTIONS ***************************************************************/
45
46 NTSTATUS PsAssignImpersonationToken(PETHREAD Thread,
47 HANDLE TokenHandle)
48 {
49 PACCESS_TOKEN Token;
50 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
51 NTSTATUS Status;
52
53 if (TokenHandle != NULL)
54 {
55 Status = ObReferenceObjectByHandle(TokenHandle,
56 0,
57 SeTokenType,
58 UserMode,
59 (PVOID*)&Token,
60 NULL);
61 if (!NT_SUCCESS(Status))
62 {
63 return(Status);
64 }
65 ImpersonationLevel = Token->ImpersonationLevel;
66 }
67 else
68 {
69 Token = NULL;
70 ImpersonationLevel = 0;
71 }
72
73 PsImpersonateClient(Thread,
74 Token,
75 0,
76 0,
77 ImpersonationLevel);
78 if (Token != NULL)
79 {
80 ObDereferenceObject(Token);
81 }
82 return(STATUS_SUCCESS);
83 }
84
85 VOID PsRevertToSelf(PETHREAD Thread)
86 {
87 if (Thread->ActiveImpersonationInfo != 0)
88 {
89 Thread->ActiveImpersonationInfo = 0;
90 ObDereferenceObject(Thread->ImpersonationInfo->Token);
91 }
92 }
93
94 VOID PsImpersonateClient(PETHREAD Thread,
95 PACCESS_TOKEN Token,
96 UCHAR b,
97 UCHAR c,
98 SECURITY_IMPERSONATION_LEVEL Level)
99 {
100 if (Token == 0)
101 {
102 if (Thread->ActiveImpersonationInfo != 0)
103 {
104 Thread->ActiveImpersonationInfo = 0;
105 if (Thread->ImpersonationInfo->Token != NULL)
106 {
107 ObDereferenceObject(Thread->ImpersonationInfo->Token);
108 }
109 }
110 return;
111 }
112 if (Thread->ActiveImpersonationInfo == 0 ||
113 Thread->ImpersonationInfo == NULL)
114 {
115 Thread->ImpersonationInfo = ExAllocatePool(NonPagedPool,
116 sizeof(PS_IMPERSONATION_INFO));
117 }
118 Thread->ImpersonationInfo->Level = Level;
119 Thread->ImpersonationInfo->Unknown2 = c;
120 Thread->ImpersonationInfo->Unknown1 = b;
121 Thread->ImpersonationInfo->Token = Token;
122 ObReferenceObjectByPointer(Token,
123 0,
124 SeTokenType,
125 KernelMode);
126 Thread->ActiveImpersonationInfo = 1;
127 }
128
129 PACCESS_TOKEN PsReferenceEffectiveToken(PETHREAD Thread,
130 PTOKEN_TYPE TokenType,
131 PUCHAR b,
132 PSECURITY_IMPERSONATION_LEVEL Level)
133 {
134 PEPROCESS Process;
135 PACCESS_TOKEN Token;
136
137 if (Thread->ActiveImpersonationInfo == 0)
138 {
139 Process = Thread->ThreadsProcess;
140 *TokenType = TokenPrimary;
141 *b = 0;
142 Token = Process->Token;
143 }
144 else
145 {
146 Token = Thread->ImpersonationInfo->Token;
147 *TokenType = TokenImpersonation;
148 *b = Thread->ImpersonationInfo->Unknown2;
149 *Level = Thread->ImpersonationInfo->Level;
150 }
151 return(Token);
152 }
153
154 NTSTATUS STDCALL NtImpersonateThread (IN HANDLE ThreadHandle,
155 IN HANDLE ThreadToImpersonateHandle,
156 IN PSECURITY_QUALITY_OF_SERVICE
157 SecurityQualityOfService)
158 {
159 PETHREAD Thread;
160 PETHREAD ThreadToImpersonate;
161 NTSTATUS Status;
162 SE_SOME_STRUCT2 b;
163
164 Status = ObReferenceObjectByHandle(ThreadHandle,
165 0,
166 PsThreadType,
167 UserMode,
168 (PVOID*)&Thread,
169 NULL);
170 if (!NT_SUCCESS(Status))
171 {
172 return(Status);
173 }
174
175 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
176 0,
177 PsThreadType,
178 UserMode,
179 (PVOID*)&ThreadToImpersonate,
180 NULL);
181 if (!NT_SUCCESS(Status))
182 {
183 ObDereferenceObject(Thread);
184 return(Status);
185 }
186
187 Status = SeCreateClientSecurity(ThreadToImpersonate,
188 SecurityQualityOfService,
189 0,
190 &b);
191 if (!NT_SUCCESS(Status))
192 {
193 ObDereferenceObject(Thread);
194 ObDereferenceObject(ThreadToImpersonate);
195 return(Status);
196 }
197
198 SeImpersonateClient(&b, Thread);
199 if (b.Token != NULL)
200 {
201 ObDereferenceObject(b.Token);
202 }
203 return(STATUS_SUCCESS);
204 }
205
206 NTSTATUS STDCALL NtOpenThreadToken(IN HANDLE ThreadHandle,
207 IN ACCESS_MASK DesiredAccess,
208 IN BOOLEAN OpenAsSelf,
209 OUT PHANDLE TokenHandle)
210 {
211 #if 0
212 PETHREAD Thread;
213 NTSTATUS Status;
214 PACCESS_TOKEN Token;
215
216 Status = ObReferenceObjectByHandle(ThreadHandle,
217 0,
218 PsThreadType,
219 UserMode,
220 (PVOID*)&Thread,
221 NULL);
222 if (!NT_SUCCESS(Status))
223 {
224 return(Status);
225 }
226
227 Token = PsReferencePrimaryToken(Thread->ThreadsProcess);
228 SepCreateImpersonationTokenDacl(Token);
229 #endif
230 return(STATUS_UNSUCCESSFUL);
231 }
232
233 PACCESS_TOKEN PsReferenceImpersonationToken(PETHREAD Thread,
234 PULONG Unknown1,
235 PULONG Unknown2,
236 SECURITY_IMPERSONATION_LEVEL*
237 Level)
238 {
239 if (Thread->ActiveImpersonationInfo == 0)
240 {
241 return(NULL);
242 }
243
244 *Level = Thread->ImpersonationInfo->Level;
245 *Unknown1 = Thread->ImpersonationInfo->Unknown1;
246 *Unknown2 = Thread->ImpersonationInfo->Unknown2;
247 ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token,
248 GENERIC_ALL,
249 SeTokenType,
250 KernelMode);
251 return(Thread->ImpersonationInfo->Token);
252 }
253
254 static VOID PiTimeoutThread(struct _KDPC *dpc,
255 PVOID Context,
256 PVOID arg1,
257 PVOID arg2 )
258 {
259 // wake up the thread, and tell it it timed out
260 NTSTATUS Status = STATUS_TIMEOUT;
261
262 DPRINT("PiTimeoutThread()\n");
263
264 KeRemoveAllWaitsThread((PETHREAD)Context, Status);
265 }
266
267 VOID PiBeforeBeginThread(VOID)
268 {
269 DPRINT("PiBeforeBeginThread()\n");
270 //KeReleaseSpinLock(&PiThreadListLock, PASSIVE_LEVEL);
271 KeLowerIrql(PASSIVE_LEVEL);
272 }
273
274 VOID PsBeginThread(PKSTART_ROUTINE StartRoutine, PVOID StartContext)
275 {
276 NTSTATUS Ret;
277
278 // KeReleaseSpinLock(&PiThreadListLock,PASSIVE_LEVEL);
279 KeLowerIrql(PASSIVE_LEVEL);
280 Ret = StartRoutine(StartContext);
281 PsTerminateSystemThread(Ret);
282 KeBugCheck(0);
283 }
284
285 VOID PiDeleteThread(PVOID ObjectBody)
286 {
287 KIRQL oldIrql;
288
289 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody);
290
291 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
292 DPRINT("Process %x(%d)\n", ((PETHREAD)ObjectBody)->ThreadsProcess,
293 ObGetReferenceCount(((PETHREAD)ObjectBody)->ThreadsProcess));
294 ObDereferenceObject(((PETHREAD)ObjectBody)->ThreadsProcess);
295 ((PETHREAD)ObjectBody)->ThreadsProcess = NULL;
296 PiNrThreads--;
297 RemoveEntryList(&((PETHREAD)ObjectBody)->Tcb.ThreadListEntry);
298 HalReleaseTask((PETHREAD)ObjectBody);
299 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
300 DPRINT("PiDeleteThread() finished\n");
301 }
302
303 VOID PiCloseThread(PVOID ObjectBody, ULONG HandleCount)
304 {
305 DPRINT("PiCloseThread(ObjectBody %x)\n", ObjectBody);
306 DPRINT("ObGetReferenceCount(ObjectBody) %d "
307 "ObGetHandleCount(ObjectBody) %d\n",
308 ObGetReferenceCount(ObjectBody),
309 ObGetHandleCount(ObjectBody));
310 }
311
312 NTSTATUS PsInitializeThread(HANDLE ProcessHandle,
313 PETHREAD* ThreadPtr,
314 PHANDLE ThreadHandle,
315 ACCESS_MASK DesiredAccess,
316 POBJECT_ATTRIBUTES ThreadAttributes)
317 {
318 PETHREAD Thread;
319 NTSTATUS Status;
320 KIRQL oldIrql;
321 PEPROCESS Process;
322
323 /*
324 * Reference process
325 */
326 if (ProcessHandle != NULL)
327 {
328 Status = ObReferenceObjectByHandle(ProcessHandle,
329 PROCESS_CREATE_THREAD,
330 PsProcessType,
331 UserMode,
332 (PVOID*)&Process,
333 NULL);
334 if (Status != STATUS_SUCCESS)
335 {
336 DPRINT("Failed at %s:%d\n",__FILE__,__LINE__);
337 return(Status);
338 }
339 }
340 else
341 {
342 Process = SystemProcess;
343 ObReferenceObjectByPointer(Process,
344 PROCESS_CREATE_THREAD,
345 PsProcessType,
346 UserMode);
347 }
348
349 /*
350 * Create and initialize thread
351 */
352 Thread = ObCreateObject(ThreadHandle,
353 DesiredAccess,
354 ThreadAttributes,
355 PsThreadType);
356 DPRINT("Thread = %x\n",Thread);
357
358 PiNrThreads++;
359
360 Thread->Tcb.State = THREAD_STATE_SUSPENDED;
361 Thread->Tcb.SuspendCount = 0;
362 Thread->Tcb.FreezeCount = 1;
363 InitializeListHead(&Thread->Tcb.ApcState.ApcListHead[0]);
364 InitializeListHead(&Thread->Tcb.ApcState.ApcListHead[1]);
365 Thread->Tcb.KernelApcDisable = 1;
366 Thread->Tcb.WaitIrql = PASSIVE_LEVEL;
367 Thread->ThreadsProcess = Process;
368 KeInitializeDpc(&Thread->Tcb.TimerDpc, PiTimeoutThread, Thread);
369 Thread->Tcb.WaitBlockList = NULL;
370 InsertTailList(&Thread->ThreadsProcess->Pcb.ThreadListHead,
371 &Thread->Tcb.ProcessThreadListEntry );
372 DPRINT1("Inserting %x into process %x list\n",
373 Thread, Thread->ThreadsProcess);
374 KeInitializeDispatcherHeader(&Thread->Tcb.DispatcherHeader,
375 InternalThreadType,
376 sizeof(ETHREAD),
377 FALSE);
378
379 InitializeListHead(&Thread->IrpList);
380 Thread->Cid.UniqueThread = (HANDLE)InterlockedIncrement(
381 &PiNextThreadUniqueId);
382 Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
383 DPRINT("Thread->Cid.UniqueThread %d\n",Thread->Cid.UniqueThread);
384
385 *ThreadPtr = Thread;
386
387 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
388 InsertTailList(&PiThreadListHead, &Thread->Tcb.ThreadListEntry);
389 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
390
391 Thread->Tcb.BasePriority = Thread->ThreadsProcess->Pcb.BasePriority;
392 Thread->Tcb.Priority = Thread->Tcb.BasePriority;
393
394 return(STATUS_SUCCESS);
395 }
396
397
398 static NTSTATUS PsCreateTeb (HANDLE ProcessHandle,
399 PNT_TEB *TebPtr,
400 PETHREAD Thread,
401 PINITIAL_TEB InitialTeb)
402 {
403 // MEMORY_BASIC_INFORMATION Info;
404 NTSTATUS Status;
405 ULONG ByteCount;
406 ULONG RegionSize;
407 ULONG TebSize;
408 PVOID TebBase;
409 NT_TEB Teb;
410
411 TebBase = (PVOID)0x7FFDE000;
412 TebSize = PAGESIZE;
413
414 while (TRUE)
415 {
416 /* The TEB must reside in user space */
417 Status = NtAllocateVirtualMemory(ProcessHandle,
418 &TebBase,
419 0,
420 &TebSize,
421 MEM_COMMIT,
422 PAGE_READWRITE);
423 if (NT_SUCCESS(Status))
424 {
425 DPRINT ("TEB allocated at %x\n", TebBase);
426 break;
427 }
428 else
429 {
430 DPRINT ("TEB allocation failed! Status %x\n",Status);
431 for(;;);
432 return(Status);
433 }
434
435 // TebBase = Info.BaseAddress - TebSize;
436 TebBase = TebBase - TebSize;
437 }
438
439 DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
440
441 /* set all pointers to and from the TEB */
442 Teb.Tib.Self = TebBase;
443 if (Thread->ThreadsProcess)
444 {
445 Teb.Peb = Thread->ThreadsProcess->Peb; /* No PEB yet!! */
446 }
447
448 /* store stack information from InitialTeb */
449 if (InitialTeb != NULL)
450 {
451 Teb.Tib.StackBase = InitialTeb->StackBase;
452 Teb.Tib.StackLimit = InitialTeb->StackLimit;
453
454 /*
455 * I don't know if this is really stored in a WNT-TEB,
456 * but it's needed to free the thread stack. (Eric Kohl)
457 */
458 Teb.StackCommit = InitialTeb->StackCommit;
459 Teb.StackCommitMax = InitialTeb->StackCommitMax;
460 Teb.StackReserved = InitialTeb->StackReserved;
461 }
462
463
464 /* more initialization */
465 Teb.Cid.UniqueThread = Thread->Cid.UniqueThread;
466 Teb.Cid.UniqueProcess = Thread->Cid.UniqueProcess;
467
468 DPRINT("sizeof(NT_TEB) %x\n", sizeof(NT_TEB));
469
470 /* write TEB data into teb page */
471 Status = NtWriteVirtualMemory(ProcessHandle,
472 TebBase,
473 &Teb,
474 sizeof(NT_TEB),
475 &ByteCount);
476
477 if (!NT_SUCCESS(Status))
478 {
479 /* free TEB */
480 DPRINT ("Writing TEB failed!\n");
481
482 RegionSize = 0;
483 NtFreeVirtualMemory(ProcessHandle,
484 TebBase,
485 &RegionSize,
486 MEM_RELEASE);
487
488 return Status;
489 }
490
491 /* FIXME: fs:[0] = TEB */
492
493 if (TebPtr != NULL)
494 {
495 // *TebPtr = (PNT_TEB)TebBase;
496 }
497
498 DPRINT ("TEB allocated at %p\n", TebBase);
499
500 return Status;
501 }
502
503
504 NTSTATUS STDCALL NtCreateThread (PHANDLE ThreadHandle,
505 ACCESS_MASK DesiredAccess,
506 POBJECT_ATTRIBUTES ObjectAttributes,
507 HANDLE ProcessHandle,
508 PCLIENT_ID Client,
509 PCONTEXT ThreadContext,
510 PINITIAL_TEB InitialTeb,
511 BOOLEAN CreateSuspended)
512 {
513 PETHREAD Thread;
514 PNT_TEB TebBase;
515 NTSTATUS Status;
516
517 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
518 ThreadHandle,ThreadContext);
519
520 Status = PsInitializeThread(ProcessHandle,&Thread,ThreadHandle,
521 DesiredAccess,ObjectAttributes);
522 if (!NT_SUCCESS(Status))
523 {
524 return(Status);
525 }
526
527 Status = HalInitTaskWithContext(Thread,ThreadContext);
528 if (!NT_SUCCESS(Status))
529 {
530 return(Status);
531 }
532
533 Status = PsCreateTeb (ProcessHandle,
534 &TebBase,
535 Thread,
536 InitialTeb);
537 if (!NT_SUCCESS(Status))
538 {
539 return(Status);
540 }
541
542 /* Attention: TebBase is in user memory space */
543 // Thread->Tcb.Teb = TebBase;
544
545 Thread->StartAddress=NULL;
546
547 if (Client!=NULL)
548 {
549 *Client=Thread->Cid;
550 }
551
552 if (!CreateSuspended)
553 {
554 DPRINT("Not creating suspended\n");
555 PsUnfreezeThread(Thread, NULL);
556 }
557 DPRINT("Thread %x\n", Thread);
558 DPRINT("ObGetReferenceCount(Thread) %d ObGetHandleCount(Thread) %x\n",
559 ObGetReferenceCount(Thread), ObGetHandleCount(Thread));
560 DPRINT("Finished PsCreateThread()\n");
561 return(STATUS_SUCCESS);
562 }
563
564
565 NTSTATUS PsCreateSystemThread(PHANDLE ThreadHandle,
566 ACCESS_MASK DesiredAccess,
567 POBJECT_ATTRIBUTES ObjectAttributes,
568 HANDLE ProcessHandle,
569 PCLIENT_ID ClientId,
570 PKSTART_ROUTINE StartRoutine,
571 PVOID StartContext)
572 /*
573 * FUNCTION: Creates a thread which executes in kernel mode
574 * ARGUMENTS:
575 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
576 * handle
577 * DesiredAccess = Requested access to the thread
578 * ObjectAttributes = Object attributes (optional)
579 * ProcessHandle = Handle of process thread will run in
580 * NULL to use system process
581 * ClientId (OUT) = Caller supplied storage for the returned client id
582 * of the thread (optional)
583 * StartRoutine = Entry point for the thread
584 * StartContext = Argument supplied to the thread when it begins
585 * execution
586 * RETURNS: Success or failure status
587 */
588 {
589 PETHREAD Thread;
590 NTSTATUS Status;
591
592 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
593 ThreadHandle,ProcessHandle);
594
595 Status = PsInitializeThread(ProcessHandle,&Thread,ThreadHandle,
596 DesiredAccess,ObjectAttributes);
597 if (!NT_SUCCESS(Status))
598 {
599 return(Status);
600 }
601
602 Thread->StartAddress=StartRoutine;
603 Status = HalInitTask(Thread,StartRoutine,StartContext);
604 if (!NT_SUCCESS(Status))
605 {
606 return(Status);
607 }
608
609 if (ClientId!=NULL)
610 {
611 *ClientId=Thread->Cid;
612 }
613
614 PsUnfreezeThread(Thread, NULL);
615
616 return(STATUS_SUCCESS);
617 }
618