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