2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Base API Server DLL
4 * FILE: subsystems/win/basesrv/dosdev.c
5 * PURPOSE: DOS Devices Management
6 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
9 /* INCLUDES *******************************************************************/
16 /* GLOBALS ********************************************************************/
18 typedef struct _BASE_DOS_DEVICE_HISTORY_ENTRY
21 UNICODE_STRING Device
;
22 UNICODE_STRING Target
;
23 } BASE_DOS_DEVICE_HISTORY_ENTRY
, *PBASE_DOS_DEVICE_HISTORY_ENTRY
;
25 static RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec
;
26 static LIST_ENTRY DosDeviceHistory
;
28 /* PRIVATE FUNCTIONS **********************************************************/
30 VOID
BaseInitDefineDosDevice(VOID
)
32 RtlInitializeCriticalSection(&BaseDefineDosDeviceCritSec
);
33 InitializeListHead(&DosDeviceHistory
);
36 VOID
BaseCleanupDefineDosDevice(VOID
)
38 PLIST_ENTRY Entry
, ListHead
;
39 PBASE_DOS_DEVICE_HISTORY_ENTRY HistoryEntry
;
41 RtlDeleteCriticalSection(&BaseDefineDosDeviceCritSec
);
43 ListHead
= &DosDeviceHistory
;
44 Entry
= ListHead
->Flink
;
45 while (Entry
!= ListHead
)
47 HistoryEntry
= (PBASE_DOS_DEVICE_HISTORY_ENTRY
)
48 CONTAINING_RECORD(Entry
,
49 BASE_DOS_DEVICE_HISTORY_ENTRY
,
55 if (HistoryEntry
->Target
.Buffer
)
57 RtlFreeHeap(BaseSrvHeap
,
59 HistoryEntry
->Target
.Buffer
);
61 if (HistoryEntry
->Device
.Buffer
)
63 RtlFreeHeap(BaseSrvHeap
,
65 HistoryEntry
->Device
.Buffer
);
67 RtlFreeHeap(BaseSrvHeap
,
74 /* PUBLIC SERVER APIS *********************************************************/
76 CSR_API(BaseSrvDefineDosDevice
)
79 PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest
= &((PBASE_API_MESSAGE
)ApiMessage
)->Data
.DefineDosDeviceRequest
;
80 OBJECT_ATTRIBUTES ObjectAttributes
;
81 HANDLE LinkHandle
= NULL
;
82 UNICODE_STRING DeviceName
= {0};
83 UNICODE_STRING RequestDeviceName
= {0};
84 UNICODE_STRING LinkTarget
= {0};
85 PUNICODE_STRING RequestLinkTarget
;
87 SID_IDENTIFIER_AUTHORITY WorldAuthority
= {SECURITY_WORLD_SID_AUTHORITY
};
88 SID_IDENTIFIER_AUTHORITY SystemAuthority
= {SECURITY_NT_AUTHORITY
};
89 PSECURITY_DESCRIPTOR SecurityDescriptor
;
95 PBASE_DOS_DEVICE_HISTORY_ENTRY HistoryEntry
;
98 BOOLEAN Matched
, AddHistory
;
102 DPRINT("BaseSrvDefineDosDevice entered, Flags:%d, DeviceName:%wZ, TargetPath:%wZ\n",
103 DefineDosDeviceRequest
->Flags
,
104 &DefineDosDeviceRequest
->DeviceName
,
105 &DefineDosDeviceRequest
->TargetPath
);
107 Matched
= AddHistory
= FALSE
;
109 AdminSid
= SystemSid
= WorldSid
= NULL
;
110 SecurityDescriptor
= NULL
;
111 ListHead
= &DosDeviceHistory
;
112 dwFlags
= DefineDosDeviceRequest
->Flags
;
114 /* Validate the flags */
115 if ( (dwFlags
& 0xFFFFFFF0) ||
116 ((dwFlags
& DDD_EXACT_MATCH_ON_REMOVE
) &&
117 !(dwFlags
& DDD_REMOVE_DEFINITION
)) )
119 return STATUS_INVALID_PARAMETER
;
122 Status
= RtlEnterCriticalSection(&BaseDefineDosDeviceCritSec
);
123 if (!NT_SUCCESS(Status
))
125 DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n",
133 RtlUpcaseUnicodeString(&RequestDeviceName
,
134 &DefineDosDeviceRequest
->DeviceName
,
136 if (!NT_SUCCESS(Status
))
139 RequestLinkTarget
= &DefineDosDeviceRequest
->TargetPath
;
140 lpBuffer
= (PWSTR
)RtlAllocateHeap(BaseSrvHeap
,
142 RequestDeviceName
.MaximumLength
+ 5 * sizeof(WCHAR
));
145 DPRINT1("Failed to allocate memory\n");
146 Status
= STATUS_NO_MEMORY
;
153 RtlInitUnicodeString(&DeviceName
,
155 InitializeObjectAttributes(&ObjectAttributes
,
157 OBJ_CASE_INSENSITIVE
,
160 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
163 if (NT_SUCCESS(Status
))
165 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
168 if (!NT_SUCCESS(Status
) &&
169 Status
== STATUS_BUFFER_TOO_SMALL
)
171 LinkTarget
.Length
= 0;
172 LinkTarget
.MaximumLength
= Length
;
173 LinkTarget
.Buffer
= (PWSTR
)
174 RtlAllocateHeap(BaseSrvHeap
,
177 if (!LinkTarget
.Buffer
)
179 DPRINT1("Failed to allocate memory\n");
180 Status
= STATUS_NO_MEMORY
;
184 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
189 if (!NT_SUCCESS(Status
))
191 DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed (Status %lx)\n",
192 &DeviceName
, Status
);
196 if ((dwFlags
& DDD_REMOVE_DEFINITION
))
198 /* If no target name specified we remove the current symlink target */
199 if (RequestLinkTarget
->Length
== 0)
203 if (dwFlags
& DDD_EXACT_MATCH_ON_REMOVE
)
204 Matched
= !RtlCompareUnicodeString(RequestLinkTarget
,
208 Matched
= RtlPrefixUnicodeString(RequestLinkTarget
,
213 if (Matched
&& IsListEmpty(ListHead
))
215 /* Current symlink target macthed and there is nothing to revert to */
216 RequestLinkTarget
= NULL
;
218 else if (Matched
&& !IsListEmpty(ListHead
))
221 * Fetch the first history entry we come across for the device name.
222 * This will become the current symlink target for the device name.
225 Entry
= ListHead
->Flink
;
226 while (Entry
!= ListHead
)
228 HistoryEntry
= (PBASE_DOS_DEVICE_HISTORY_ENTRY
)
229 CONTAINING_RECORD(Entry
,
230 BASE_DOS_DEVICE_HISTORY_ENTRY
,
233 !RtlCompareUnicodeString(&RequestDeviceName
,
234 &HistoryEntry
->Device
,
238 RemoveEntryList(&HistoryEntry
->Entry
);
239 RequestLinkTarget
= &HistoryEntry
->Target
;
242 Entry
= Entry
->Flink
;
246 /* Nothing to revert to so delete the symlink */
248 RequestLinkTarget
= NULL
;
253 * Locate a previous symlink target as we did not get
254 * a hit earlier. If we find one we need to remove it.
256 Entry
= ListHead
->Flink
;
257 while (Entry
!= ListHead
)
259 HistoryEntry
= (PBASE_DOS_DEVICE_HISTORY_ENTRY
)
260 CONTAINING_RECORD(Entry
,
261 BASE_DOS_DEVICE_HISTORY_ENTRY
,
264 !RtlCompareUnicodeString(&RequestDeviceName
,
265 &HistoryEntry
->Device
,
270 Entry
= Entry
->Flink
;
275 if (dwFlags
& DDD_EXACT_MATCH_ON_REMOVE
)
277 if (!RtlCompareUnicodeString(RequestLinkTarget
,
278 &HistoryEntry
->Target
,
284 else if (RtlPrefixUnicodeString(RequestLinkTarget
,
285 &HistoryEntry
->Target
,
293 RemoveEntryList(&HistoryEntry
->Entry
);
296 Entry
= Entry
->Flink
;
300 /* Leave existing symlink as is */
302 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
304 Status
= STATUS_SUCCESS
;
313 Status
= NtMakeTemporaryObject(LinkHandle
);
314 if (!NT_SUCCESS(Status
))
316 DPRINT1("NtMakeTemporaryObject(%wZ) failed (Status %lx)\n",
317 &DeviceName
, Status
);
321 Status
= NtClose(LinkHandle
);
323 if (!NT_SUCCESS(Status
))
325 DPRINT1("NtClose(%wZ) failed (Status %lx)\n",
326 &DeviceName
, Status
);
331 /* Don't create symlink if we don't have a target */
332 if (!RequestLinkTarget
|| RequestLinkTarget
->Length
== 0)
337 HistoryEntry
= (PBASE_DOS_DEVICE_HISTORY_ENTRY
)
338 RtlAllocateHeap(BaseSrvHeap
,
340 sizeof(BASE_DOS_DEVICE_HISTORY_ENTRY
));
343 DPRINT1("Failed to allocate memory\n");
344 Status
= STATUS_NO_MEMORY
;
348 HistoryEntry
->Target
.Buffer
=
349 RtlAllocateHeap(BaseSrvHeap
,
352 if (!HistoryEntry
->Target
.Buffer
)
354 DPRINT1("Failed to allocate memory\n");
355 Status
= STATUS_NO_MEMORY
;
358 HistoryEntry
->Target
.Length
=
359 HistoryEntry
->Target
.MaximumLength
=
361 RtlCopyUnicodeString(&HistoryEntry
->Target
,
364 HistoryEntry
->Device
.Buffer
=
365 RtlAllocateHeap(BaseSrvHeap
,
367 RequestDeviceName
.Length
);
368 if (!HistoryEntry
->Device
.Buffer
)
370 DPRINT1("Failed to allocate memory\n");
371 Status
= STATUS_NO_MEMORY
;
374 HistoryEntry
->Device
.Length
=
375 HistoryEntry
->Device
.MaximumLength
=
376 RequestDeviceName
.Length
;
377 RtlCopyUnicodeString(&HistoryEntry
->Device
,
380 /* Remember previous symlink target for this device */
381 InsertHeadList(ListHead
,
382 &HistoryEntry
->Entry
);
386 RtlAllocateAndInitializeSid(&WorldAuthority
,
398 RtlAllocateAndInitializeSid(&SystemAuthority
,
400 SECURITY_LOCAL_SYSTEM_RID
,
410 RtlAllocateAndInitializeSid(&SystemAuthority
,
412 SECURITY_BUILTIN_DOMAIN_RID
,
413 DOMAIN_ALIAS_RID_ADMINS
,
422 SidLength
= RtlLengthSid(SystemSid
) +
423 RtlLengthSid(AdminSid
) +
424 RtlLengthSid(WorldSid
);
425 Length
= sizeof(ACL
) + SidLength
+ 3 * sizeof(ACCESS_ALLOWED_ACE
);
427 SecurityDescriptor
= RtlAllocateHeap(BaseSrvHeap
,
429 SECURITY_DESCRIPTOR_MIN_LENGTH
+ Length
);
430 if (!SecurityDescriptor
)
432 DPRINT1("Failed to allocate memory\n");
433 Status
= STATUS_NO_MEMORY
;
437 Dacl
= (PACL
)((ULONG_PTR
)SecurityDescriptor
+ SECURITY_DESCRIPTOR_MIN_LENGTH
);
438 Status
= RtlCreateSecurityDescriptor(SecurityDescriptor
,
439 SECURITY_DESCRIPTOR_REVISION
);
440 if (!NT_SUCCESS(Status
))
442 DPRINT1("RtlCreateSecurityDescriptor() failed (Status %lx)\n", Status
);
446 Status
= RtlCreateAcl(Dacl
,
449 if (!NT_SUCCESS(Status
))
451 DPRINT1("RtlCreateAcl() failed (Status %lx)\n", Status
);
455 RtlAddAccessAllowedAce(Dacl
,
459 RtlAddAccessAllowedAce(Dacl
,
463 RtlAddAccessAllowedAce(Dacl
,
465 STANDARD_RIGHTS_READ
,
468 Status
= RtlSetDaclSecurityDescriptor(SecurityDescriptor
,
472 if (!NT_SUCCESS(Status
))
474 DPRINT1("RtlSetDaclSecurityDescriptor() failed (Status %lx)\n", Status
);
478 InitializeObjectAttributes(&ObjectAttributes
,
480 OBJ_CASE_INSENSITIVE
,
483 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
484 SYMBOLIC_LINK_ALL_ACCESS
,
487 if (NT_SUCCESS(Status
))
489 Status
= NtMakePermanentObject(LinkHandle
);
490 if (!NT_SUCCESS(Status
))
492 DPRINT1("NtMakePermanentObject(%wZ) failed (Status %lx)\n",
493 &DeviceName
, Status
);
498 DPRINT1("NtCreateSymbolicLinkObject(%wZ) failed (Status %lx)\n",
499 &DeviceName
, Status
);
504 RtlLeaveCriticalSection(&BaseDefineDosDeviceCritSec
);
505 if (DeviceName
.Buffer
)
507 RtlFreeHeap(BaseSrvHeap
,
511 if (LinkTarget
.Buffer
)
513 RtlFreeHeap(BaseSrvHeap
,
517 if (SecurityDescriptor
)
519 RtlFreeHeap(BaseSrvHeap
,
524 if (LinkHandle
) NtClose(LinkHandle
);
525 if (SystemSid
) RtlFreeSid(SystemSid
);
526 if (AdminSid
) RtlFreeSid(AdminSid
);
527 if (WorldSid
) RtlFreeSid(WorldSid
);
529 RtlFreeUnicodeString(&RequestDeviceName
);
533 if (HistoryEntry
->Target
.Buffer
)
535 RtlFreeHeap(BaseSrvHeap
,
537 HistoryEntry
->Target
.Buffer
);
539 if (HistoryEntry
->Device
.Buffer
)
541 RtlFreeHeap(BaseSrvHeap
,
543 HistoryEntry
->Device
.Buffer
);
545 RtlFreeHeap(BaseSrvHeap
,
552 DPRINT("BaseSrvDefineDosDevice exit, Status: 0x%x\n", Status
);