638769fad282788f6ab99f2a738aee549bb6feeb
[reactos.git] / win32ss / user / win32csr / file.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: subsys/csrss/win32csr/file.c
5 * PURPOSE: File handling
6 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
7 * NOTE: Belongs to basesrv.dll
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <w32csr.h>
13 #define NDEBUG
14 #include <debug.h>
15 #include "file.h"
16
17 /* GLOBALS *******************************************************************/
18
19 typedef BOOL (WINAPI *PUSER_SOUND_SENTRY)(VOID);
20 BOOL
21 WINAPI
22 FirstSoundSentry(VOID);
23
24 UINT CsrGetTempFileUnique;
25 LIST_ENTRY DosDeviceHistory;
26 RTL_CRITICAL_SECTION Win32CsrDefineDosDeviceCritSec;
27 PUSER_SOUND_SENTRY _UserSoundSentry = FirstSoundSentry;
28
29 /* FUNCTIONS *****************************************************************/
30
31 BOOL
32 WINAPI
33 FailSoundSentry(VOID)
34 {
35 /* In case the function can't be found/is unimplemented */
36 return FALSE;
37 }
38
39 BOOL
40 WINAPI
41 FirstSoundSentry(VOID)
42 {
43 UNICODE_STRING DllString = RTL_CONSTANT_STRING(L"winsrv");
44 STRING FuncString = RTL_CONSTANT_STRING("_UserSoundSentry");
45 HANDLE DllHandle;
46 NTSTATUS Status;
47 PUSER_SOUND_SENTRY NewSoundSentry = FailSoundSentry;
48
49 /* Load winsrv manually */
50 Status = LdrGetDllHandle(NULL, NULL, &DllString, &DllHandle);
51 if (NT_SUCCESS(Status))
52 {
53 /* If it was found, get SoundSentry export */
54 Status = LdrGetProcedureAddress(DllHandle,
55 &FuncString,
56 0,
57 (PVOID*)&NewSoundSentry);
58 }
59
60 /* Set it as the callback for the future, and call it */
61 _UserSoundSentry = NewSoundSentry;
62 return _UserSoundSentry();
63 }
64
65 CSR_API(CsrSoundSentry)
66 {
67 /* Call the API and see if it suceeds */
68 return _UserSoundSentry() ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
69 }
70
71 CSR_API(CsrGetTempFile)
72 {
73 DPRINT("CsrGetTempFile entered\n");
74
75 /* Return 16-bits ID */
76 Request->Data.GetTempFile.UniqueID = (++CsrGetTempFileUnique & 0xFFFF);
77
78 DPRINT("Returning: %u\n", Request->Data.GetTempFile.UniqueID);
79
80 return STATUS_SUCCESS;
81 }
82
83 CSR_API(CsrDefineDosDevice)
84 {
85 OBJECT_ATTRIBUTES ObjectAttributes;
86 HANDLE LinkHandle = NULL;
87 NTSTATUS Status;
88 UNICODE_STRING DeviceName = {0};
89 UNICODE_STRING RequestDeviceName = {0};
90 UNICODE_STRING LinkTarget = {0};
91 PUNICODE_STRING RequestLinkTarget;
92 ULONG Length;
93 SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
94 SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
95 PSECURITY_DESCRIPTOR SecurityDescriptor;
96 PACL Dacl;
97 PSID AdminSid;
98 PSID SystemSid;
99 PSID WorldSid;
100 ULONG SidLength;
101 PCSRSS_DOS_DEVICE_HISTORY_ENTRY HistoryEntry;
102 PLIST_ENTRY Entry;
103 PLIST_ENTRY ListHead;
104 BOOLEAN Matched, AddHistory;
105 DWORD dwFlags;
106 PWSTR lpBuffer;
107
108 DPRINT("CsrDefineDosDevice entered, Flags:%d, DeviceName:%wZ, TargetName:%wZ\n",
109 Request->Data.DefineDosDeviceRequest.dwFlags,
110 &Request->Data.DefineDosDeviceRequest.DeviceName,
111 &Request->Data.DefineDosDeviceRequest.TargetName);
112
113 Matched = AddHistory = FALSE;
114 HistoryEntry = NULL;
115 AdminSid = SystemSid = WorldSid = NULL;
116 SecurityDescriptor = NULL;
117 ListHead = &DosDeviceHistory;
118 dwFlags = Request->Data.DefineDosDeviceRequest.dwFlags;
119
120 /* Validate the flags */
121 if ( (dwFlags & 0xFFFFFFF0) ||
122 ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
123 ! (dwFlags & DDD_REMOVE_DEFINITION)) )
124 {
125 return STATUS_INVALID_PARAMETER;
126 }
127
128 Status = RtlEnterCriticalSection(&Win32CsrDefineDosDeviceCritSec);
129 if (! NT_SUCCESS(Status))
130 {
131 DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n",
132 Status);
133 return Status;
134 }
135
136 _SEH2_TRY
137 {
138 Status =
139 RtlUpcaseUnicodeString(&RequestDeviceName,
140 &Request->Data.DefineDosDeviceRequest.DeviceName,
141 TRUE);
142 if (! NT_SUCCESS(Status))
143 _SEH2_LEAVE;
144
145 RequestLinkTarget =
146 &Request->Data.DefineDosDeviceRequest.TargetName;
147 lpBuffer = (PWSTR) RtlAllocateHeap(Win32CsrApiHeap,
148 HEAP_ZERO_MEMORY,
149 RequestDeviceName.MaximumLength + 5 * sizeof(WCHAR));
150 if (! lpBuffer)
151 {
152 DPRINT1("Failed to allocate memory\n");
153 Status = STATUS_NO_MEMORY;
154 _SEH2_LEAVE;
155 }
156
157 swprintf(lpBuffer,
158 L"\\??\\%wZ",
159 &RequestDeviceName);
160 RtlInitUnicodeString(&DeviceName,
161 lpBuffer);
162 InitializeObjectAttributes(&ObjectAttributes,
163 &DeviceName,
164 OBJ_CASE_INSENSITIVE,
165 NULL,
166 NULL);
167 Status = NtOpenSymbolicLinkObject(&LinkHandle,
168 DELETE | 0x1,
169 &ObjectAttributes);
170 if (NT_SUCCESS(Status))
171 {
172 Status = NtQuerySymbolicLinkObject(LinkHandle,
173 &LinkTarget,
174 &Length);
175 if (! NT_SUCCESS(Status) &&
176 Status == STATUS_BUFFER_TOO_SMALL)
177 {
178 LinkTarget.Length = 0;
179 LinkTarget.MaximumLength = Length;
180 LinkTarget.Buffer = (PWSTR)
181 RtlAllocateHeap(Win32CsrApiHeap,
182 HEAP_ZERO_MEMORY,
183 Length);
184 if (! LinkTarget.Buffer)
185 {
186 DPRINT1("Failed to allocate memory\n");
187 Status = STATUS_NO_MEMORY;
188 _SEH2_LEAVE;
189 }
190
191 Status = NtQuerySymbolicLinkObject(LinkHandle,
192 &LinkTarget,
193 &Length);
194 }
195
196 if (! NT_SUCCESS(Status))
197 {
198 DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed (Status %lx)\n",
199 &DeviceName, Status);
200 _SEH2_LEAVE;
201 }
202
203 if ((dwFlags & DDD_REMOVE_DEFINITION))
204 {
205 /* If no target name specified we remove the current symlink target */
206 if (RequestLinkTarget->Length == 0)
207 Matched = TRUE;
208 else
209 {
210 if (dwFlags & DDD_EXACT_MATCH_ON_REMOVE)
211 Matched = ! RtlCompareUnicodeString(RequestLinkTarget,
212 &LinkTarget,
213 TRUE);
214 else
215 Matched = RtlPrefixUnicodeString(RequestLinkTarget,
216 &LinkTarget,
217 TRUE);
218 }
219
220 if (Matched && IsListEmpty(ListHead))
221 {
222 /* Current symlink target macthed and there is nothing to revert to */
223 RequestLinkTarget = NULL;
224 }
225 else if (Matched && ! IsListEmpty(ListHead))
226 {
227 /* Fetch the first history entry we come across for the device name */
228 /* This will become the current symlink target for the device name */
229 Matched = FALSE;
230 Entry = ListHead->Flink;
231 while (Entry != ListHead)
232 {
233 HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY)
234 CONTAINING_RECORD(Entry,
235 CSRSS_DOS_DEVICE_HISTORY_ENTRY,
236 Entry);
237 Matched =
238 ! RtlCompareUnicodeString(&RequestDeviceName,
239 &HistoryEntry->Device,
240 FALSE);
241 if (Matched)
242 {
243 RemoveEntryList(&HistoryEntry->Entry);
244 RequestLinkTarget = &HistoryEntry->Target;
245 break;
246 }
247 Entry = Entry->Flink;
248 HistoryEntry = NULL;
249 }
250
251 /* Nothing to revert to so delete the symlink */
252 if (! Matched)
253 RequestLinkTarget = NULL;
254 }
255 else if (! Matched)
256 {
257 /* Locate a previous symlink target as we did not get a hit earlier */
258 /* If we find one we need to remove it */
259 Entry = ListHead->Flink;
260 while (Entry != ListHead)
261 {
262 HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY)
263 CONTAINING_RECORD(Entry,
264 CSRSS_DOS_DEVICE_HISTORY_ENTRY,
265 Entry);
266 Matched =
267 ! RtlCompareUnicodeString(&RequestDeviceName,
268 &HistoryEntry->Device,
269 FALSE);
270 if (! Matched)
271 {
272 HistoryEntry = NULL;
273 Entry = Entry->Flink;
274 continue;
275 }
276
277 Matched = FALSE;
278 if (dwFlags & DDD_EXACT_MATCH_ON_REMOVE)
279 {
280 if (! RtlCompareUnicodeString(RequestLinkTarget,
281 &HistoryEntry->Target,
282 TRUE))
283 {
284 Matched = TRUE;
285 }
286 }
287 else if (RtlPrefixUnicodeString(RequestLinkTarget,
288 &HistoryEntry->Target,
289 TRUE))
290 {
291 Matched = TRUE;
292 }
293
294 if (Matched)
295 {
296 RemoveEntryList(&HistoryEntry->Entry);
297 break;
298 }
299 Entry = Entry->Flink;
300 HistoryEntry = NULL;
301 }
302
303 /* Leave existing symlink as is */
304 if (! Matched)
305 Status = STATUS_OBJECT_NAME_NOT_FOUND;
306 else
307 Status = STATUS_SUCCESS;
308 _SEH2_LEAVE;
309 }
310 }
311 else
312 {
313 AddHistory = TRUE;
314 }
315
316 Status = NtMakeTemporaryObject(LinkHandle);
317 if (! NT_SUCCESS(Status))
318 {
319 DPRINT1("NtMakeTemporaryObject(%wZ) failed (Status %lx)\n",
320 &DeviceName, Status);
321 _SEH2_LEAVE;
322 }
323
324 Status = NtClose(LinkHandle);
325 LinkHandle = NULL;
326 if (! NT_SUCCESS(Status))
327 {
328 DPRINT1("NtClose(%wZ) failed (Status %lx)\n",
329 &DeviceName, Status);
330 _SEH2_LEAVE;
331 }
332 }
333
334 /* Don't create symlink if we don't have a target */
335 if (! RequestLinkTarget || RequestLinkTarget->Length == 0)
336 _SEH2_LEAVE;
337
338 if (AddHistory)
339 {
340 HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY)
341 RtlAllocateHeap(Win32CsrApiHeap,
342 HEAP_ZERO_MEMORY,
343 sizeof(CSRSS_DOS_DEVICE_HISTORY_ENTRY));
344 if (! HistoryEntry)
345 {
346 DPRINT1("Failed to allocate memory\n");
347 Status = STATUS_NO_MEMORY;
348 _SEH2_LEAVE;
349 }
350
351 HistoryEntry->Target.Buffer =
352 RtlAllocateHeap(Win32CsrApiHeap,
353 HEAP_ZERO_MEMORY,
354 LinkTarget.Length);
355 if (! HistoryEntry->Target.Buffer)
356 {
357 DPRINT1("Failed to allocate memory\n");
358 Status = STATUS_NO_MEMORY;
359 _SEH2_LEAVE;
360 }
361 HistoryEntry->Target.Length =
362 HistoryEntry->Target.MaximumLength =
363 LinkTarget.Length;
364 RtlCopyUnicodeString(&HistoryEntry->Target,
365 &LinkTarget);
366
367 HistoryEntry->Device.Buffer =
368 RtlAllocateHeap(Win32CsrApiHeap,
369 HEAP_ZERO_MEMORY,
370 RequestDeviceName.Length);
371 if (! HistoryEntry->Device.Buffer)
372 {
373 DPRINT1("Failed to allocate memory\n");
374 Status = STATUS_NO_MEMORY;
375 _SEH2_LEAVE;
376 }
377 HistoryEntry->Device.Length =
378 HistoryEntry->Device.MaximumLength =
379 RequestDeviceName.Length;
380 RtlCopyUnicodeString(&HistoryEntry->Device,
381 &RequestDeviceName);
382
383 /* Remember previous symlink target for this device */
384 InsertHeadList(ListHead,
385 &HistoryEntry->Entry);
386 HistoryEntry = NULL;
387 }
388
389 RtlAllocateAndInitializeSid(&WorldAuthority,
390 1,
391 SECURITY_WORLD_RID,
392 SECURITY_NULL_RID,
393 SECURITY_NULL_RID,
394 SECURITY_NULL_RID,
395 SECURITY_NULL_RID,
396 SECURITY_NULL_RID,
397 SECURITY_NULL_RID,
398 SECURITY_NULL_RID,
399 &WorldSid);
400
401 RtlAllocateAndInitializeSid(&SystemAuthority,
402 1,
403 SECURITY_LOCAL_SYSTEM_RID,
404 SECURITY_NULL_RID,
405 SECURITY_NULL_RID,
406 SECURITY_NULL_RID,
407 SECURITY_NULL_RID,
408 SECURITY_NULL_RID,
409 SECURITY_NULL_RID,
410 SECURITY_NULL_RID,
411 &SystemSid);
412
413 RtlAllocateAndInitializeSid(&SystemAuthority,
414 2,
415 SECURITY_BUILTIN_DOMAIN_RID,
416 DOMAIN_ALIAS_RID_ADMINS,
417 SECURITY_NULL_RID,
418 SECURITY_NULL_RID,
419 SECURITY_NULL_RID,
420 SECURITY_NULL_RID,
421 SECURITY_NULL_RID,
422 SECURITY_NULL_RID,
423 &AdminSid);
424
425 SidLength = RtlLengthSid(SystemSid) +
426 RtlLengthSid(AdminSid) +
427 RtlLengthSid(WorldSid);
428 Length = sizeof(ACL) + SidLength + 3 * sizeof(ACCESS_ALLOWED_ACE);
429
430 SecurityDescriptor = RtlAllocateHeap(Win32CsrApiHeap,
431 0,
432 SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
433 if (! SecurityDescriptor)
434 {
435 DPRINT1("Failed to allocate memory\n");
436 Status = STATUS_NO_MEMORY;
437 _SEH2_LEAVE;
438 }
439
440 Dacl = (PACL)((ULONG_PTR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
441 Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
442 SECURITY_DESCRIPTOR_REVISION);
443 if (! NT_SUCCESS(Status))
444 {
445 DPRINT1("RtlCreateSecurityDescriptor() failed (Status %lx)\n",
446 Status);
447 _SEH2_LEAVE;
448 }
449
450 Status = RtlCreateAcl(Dacl,
451 Length,
452 ACL_REVISION);
453 if (! NT_SUCCESS(Status))
454 {
455 DPRINT1("RtlCreateAcl() failed (Status %lx)\n",
456 Status);
457 _SEH2_LEAVE;
458 }
459
460 (void) RtlAddAccessAllowedAce(Dacl,
461 ACL_REVISION,
462 GENERIC_ALL,
463 SystemSid);
464 (void) RtlAddAccessAllowedAce(Dacl,
465 ACL_REVISION,
466 GENERIC_ALL,
467 AdminSid);
468 (void) RtlAddAccessAllowedAce(Dacl,
469 ACL_REVISION,
470 STANDARD_RIGHTS_READ,
471 WorldSid);
472
473 Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
474 TRUE,
475 Dacl,
476 FALSE);
477 if (! NT_SUCCESS(Status))
478 {
479 DPRINT1("RtlSetDaclSecurityDescriptor() failed (Status %lx)\n",
480 Status);
481 _SEH2_LEAVE;
482 }
483
484 InitializeObjectAttributes(&ObjectAttributes,
485 &DeviceName,
486 OBJ_CASE_INSENSITIVE,
487 NULL,
488 SecurityDescriptor);
489 Status = NtCreateSymbolicLinkObject(&LinkHandle,
490 SYMBOLIC_LINK_ALL_ACCESS,
491 &ObjectAttributes,
492 RequestLinkTarget);
493 if (NT_SUCCESS(Status))
494 {
495 Status = NtMakePermanentObject(LinkHandle);
496 if (! NT_SUCCESS(Status))
497 {
498 DPRINT1("NtMakePermanentObject(%wZ) failed (Status %lx)\n",
499 &DeviceName, Status);
500 }
501 }
502 else
503 {
504 DPRINT1("NtCreateSymbolicLinkObject(%wZ) failed (Status %lx)\n",
505 &DeviceName, Status);
506 }
507 }
508 _SEH2_FINALLY
509 {
510 (void) RtlLeaveCriticalSection(&Win32CsrDefineDosDeviceCritSec);
511 if (DeviceName.Buffer)
512 (void) RtlFreeHeap(Win32CsrApiHeap,
513 0,
514 DeviceName.Buffer);
515 if (LinkTarget.Buffer)
516 (void) RtlFreeHeap(Win32CsrApiHeap,
517 0,
518 LinkTarget.Buffer);
519 if (SecurityDescriptor)
520 (void) RtlFreeHeap(Win32CsrApiHeap,
521 0,
522 SecurityDescriptor);
523 if (LinkHandle)
524 (void) NtClose(LinkHandle);
525 if (SystemSid)
526 (void) RtlFreeSid(SystemSid);
527 if (AdminSid)
528 (void) RtlFreeSid(AdminSid);
529 if (WorldSid)
530 (void) RtlFreeSid(WorldSid);
531 RtlFreeUnicodeString(&RequestDeviceName);
532 if (HistoryEntry)
533 {
534 if (HistoryEntry->Target.Buffer)
535 (void) RtlFreeHeap(Win32CsrApiHeap,
536 0,
537 HistoryEntry->Target.Buffer);
538 if (HistoryEntry->Device.Buffer)
539 (void) RtlFreeHeap(Win32CsrApiHeap,
540 0,
541 HistoryEntry->Device.Buffer);
542 (void) RtlFreeHeap(Win32CsrApiHeap,
543 0,
544 HistoryEntry);
545 }
546 }
547 _SEH2_END
548
549 DPRINT("CsrDefineDosDevice Exit, Statux: 0x%x\n", Status);
550 return Status;
551 }
552
553 void CsrCleanupDefineDosDevice(void)
554 {
555 PLIST_ENTRY Entry, ListHead;
556 PCSRSS_DOS_DEVICE_HISTORY_ENTRY HistoryEntry;
557
558 (void) RtlDeleteCriticalSection(&Win32CsrDefineDosDeviceCritSec);
559
560 ListHead = &DosDeviceHistory;
561 Entry = ListHead->Flink;
562 while (Entry != ListHead)
563 {
564 HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY)
565 CONTAINING_RECORD(Entry,
566 CSRSS_DOS_DEVICE_HISTORY_ENTRY,
567 Entry);
568 Entry = Entry->Flink;
569
570 if (HistoryEntry)
571 {
572 if (HistoryEntry->Target.Buffer)
573 (void) RtlFreeHeap(Win32CsrApiHeap,
574 0,
575 HistoryEntry->Target.Buffer);
576 if (HistoryEntry->Device.Buffer)
577 (void) RtlFreeHeap(Win32CsrApiHeap,
578 0,
579 HistoryEntry->Device.Buffer);
580 (void) RtlFreeHeap(Win32CsrApiHeap,
581 0,
582 HistoryEntry);
583 }
584 }
585 }
586 /* EOF */