https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8d35887c02b97a7faec2b…
commit 8d35887c02b97a7faec2ba6cb84ebd032a34f50f
Author: Andrei Miloiu <miloiuandrei(a)gmail.com>
AuthorDate: Tue Aug 22 22:37:14 2023 +0300
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Aug 22 21:37:14 2023 +0200
[DISKPART][MC] Update Romanian (ro-RO) translation for message table (#5485)
---
base/system/diskpart/diskpart_msg.mc | 874 ++++++++++++++++++-----------------
1 file changed, 448 insertions(+), 426 deletions(-)
diff --git a/base/system/diskpart/diskpart_msg.mc b/base/system/diskpart/diskpart_msg.mc
index 5fe3d2deeac..41ac3a06fd1 100644
--- a/base/system/diskpart/diskpart_msg.mc
+++ b/base/system/diskpart/diskpart_msg.mc
@@ -125,26 +125,27 @@ Example:
ACTIVE
.
Language=Romanian
- On disks with master boot record (MBR) disk formatting, marks
- the partition with focus as active.
+ Pe discurile cu Registrul principal de inițializare (MBR) formatarea
+ discului marchează partiția în cauză ca activă.
-Syntax: ACTIVE
+Sintaxă: ACTIVE
- Writes a value to the disk which is read by the basic input/output
- system (BIOS) at boot. This value specifies that the partition is
- a valid system partition.
+ Scrie o valoare pe disc care este citită de Sistemul de
+ intrare/ieșire de bază (BIOS) la inițializare. Această valoare specifică
+ faptul că partiția este o partiție de sistem validă.
- A partition must be selected for this operation to succeed.
+ O partiție trebuie să fie selectată pentru această operațiune să fie cu
+ succes.
- Caution:
+ Atenție:
- DiskPart verifies only that the partition is capable of containing the
- operating system startup files. DiskPart does not check the contents of
- the partition. If you mistakenly mark a partition as active and it does
- not contain the operating system startup files, your computer might not
- start.
+ DiskPart doar verifică dacă partiția este capabilă să conțină fișierele
+ de pornire ale sistemului de operare. DiskPart nu verifică coținutul
+ partiției. Dacă ați marcat în mod eronat o partiție ca activă și nu
+ conține fișierele de pornire ale sistemului de operare, calculatorul
+ dumneavostră ar putea să nu pornească.
-Example:
+De exemplu:
ACTIVE
.
@@ -285,7 +286,7 @@ Language=Portugese
<Add ADD command help text here>
.
Language=Romanian
-<Add ADD command help text here>
+<Adăugați aici textul de ajutor pentru comanda ADD>
.
Language=Russian
<Add ADD command help text here>
@@ -321,7 +322,7 @@ Language=Portugese
<Add ASSIGN command help text here>
.
Language=Romanian
-<Add ASSIGN command help text here>
+<Adăugați aici textul de ajutor pentru comanda ASSIGN>
.
Language=Russian
<Add ASSIGN command help text here>
@@ -357,7 +358,7 @@ Language=Portugese
<Add ATTACH command help text here>
.
Language=Romanian
-<Add ATTACH command help text here>
+<Adăugați aici textul de ajutor pentru comanda ATTACH>
.
Language=Russian
<Add ATTACH command help text here>
@@ -393,7 +394,7 @@ Language=Portugese
<Add ATTRIBUTES command help text here>
.
Language=Romanian
-<Add ATTRIBUTES command help text here>
+<Adăugați aici textul de ajutor pentru comanda ATTRIBUTES>
.
Language=Russian
<Add ATTRIBUTES command help text here>
@@ -429,7 +430,7 @@ Language=Portugese
<Add AUTOMOUNT command help text here>
.
Language=Romanian
-<Add AUTOMOUNT command help text here>
+<Adăugați aici textul de ajutor pentru comanda AUTOMOUNT>
.
Language=Russian
<Add AUTOMOUNT command help text here>
@@ -466,7 +467,7 @@ Language=Portugese
<Add BREAK command help text here>
.
Language=Romanian
-<Add BREAK command help text here>
+<Adăugați aici textul de ajutor pentru comanda BREAK>
.
Language=Russian
<Add BREAK command help text here>
@@ -576,23 +577,24 @@ Example:
CLEAN
.
Language=Romanian
- Removes any and all partition or volume formatting from the disk with
- focus.
+ Șterge orice și întreaga formatare a partiției sau a volumului din
+ discul în cauză.
-Syntax: CLEAN [ALL]
+Sintaxă: CLEAN [ALL]
- ALL Specifies that each and every byte\sector on the disk is set to
- zero, which completely deletes all data contained on the disk.
+ ALL Specifică faptul că fiecare octet/sector de pe disc este setat
+ pe zero, ceea ce șterge complet toate datele conținute pe disc.
- On master boot record (MBR) disks, only the MBR partitioning information
- and hidden sector information are overwritten. On GUID partition table
- (GPT) disks, the GPT partitioning information, including the Protective
- MBR, is overwritten. If the ALL parameter is not used, the first 1MB
- and the last 1MB of the disk are zeroed. This erases any disk formatting
- that had been previously applied to the disk. The disk's state after
- cleaning the disk is 'UNINITIALIZED'.
+ Pe discurile cu Registrul principal de inițializare (MBR), sunt suprascrise
+ numai informațiile despre partiționarea MBR și informațiile despre
+ sectoarele ascunse. Pe discurile cu tabel de partiție GUID (GPT),
+ informațiile de partiționare GPT, incluzând MBR protectiv, sunt
+ suprascrise. Dacă parametrul ALL nu e folosit, primul 1 Mo și ultimul 1 Mo
+ al discului sunt puse la valoarea zero. Aceasta șterge orice formatare a
+ discului ce a fost aplicată anterior discului. Starea discului după ce
+ este curățat discul este „UNINITIALIZED” (neinițializat).
-Example:
+De exemplu:
CLEAN
.
@@ -718,7 +720,7 @@ Language=Portugese
<Add COMPACT command help text here>
.
Language=Romanian
-<Add COMPACT command help text here>
+<Adăugați aici textul de ajutor pentru comanda COMPACT>
.
Language=Russian
<Add COMPACT command help text here>
@@ -754,7 +756,7 @@ Language=Portugese
<Add CONVERT command help text here>
.
Language=Romanian
-<Add CONVERT command help text here>
+<Adăugați aici textul de ajutor pentru comanda CONVERT>
.
Language=Russian
<Add CONVERT command help text here>
@@ -790,7 +792,7 @@ Language=Portugese
<Add CREATE PARTITION EFI command help text here>
.
Language=Romanian
-<Add CREATE PARTITION EFI command help text here>
+<Adăugați aici textul de ajutor pentru comanda CREATE PARTITION EFI>
.
Language=Russian
<Add CREATE PARTITION EFI command help text here>
@@ -972,39 +974,41 @@ Example:
CREATE PARTITION EXTENDED SIZE=1000
.
Language=Romanian
- Creates an extended partition on the disk with focus.
- Applies to master boot record (MBR) disks only.
+ Crează o partiție extinsă pe discul în cauză.
+ Se aplică doar la discurile cu Registrul principal de inițializare (MBR).
-Syntax: CREATE PARTITION EXTENDED [SIZE=<N>] [OFFSET=<N>] [ALIGN=<N>] [NOERR]
+Sintaxă: CREATE PARTITION EXTENDED [SIZE=<N>] [OFFSET=<N>] [ALIGN=<N>] [NOERR]
- SIZE=<N> The size of the partition in megabytes (MB). If no size is
- given, the partition continues until there is no more free
- space in the extended partition.
+ SIZE=<N> Mărimea partiției în megaocteți (Mo). Dacă nu este dată nicio
+ mărime, partiția continuă până când nu mai este spațiu liber
+ în partiția extinsă.
- OFFSET=<N> The offset, in kilobytes (KB), at which the partition is
- created. If no offset is given, the partition will start
- at the beginning of the first free space on the disk that
- is large enough to hold the new partition.
+ OFFSET=<N> Decalajul, în kiloocteți (Ko), la care partiția este creată.
+ Dacă nu este dat niciun decalaj, partiția va începe de la
+ primul spațiu liber de pe disc ce este suficient de mare ca
+ să țină noua partiție.
- ALIGN=<N> Typically used with hardware RAID Logical Unit Number (LUN)
- arrays to improve performance. The partition offset will be
- a multiple of <N>. If the OFFSET parameter is specified, it
- will be rounded to the closest multiple of <N>.
+ ALIGN=<N> De obicei, folosit cu matrici de dispozitive cu Număr de
+ unitate logică (LUN) RAID pentru a îmbunătăți performanța.
+ Decalajul partiției va fi un multiplu a lui <N>. Dacă este
+ specificat parametrul OFFSET, va fi rotunjit la cel mai
+ apropiat multiplu a lui <N>.
- NOERR For scripting only. When an error is encountered, DiskPart
- continues to process commands as if the error did not occur.
- Without the NOERR parameter, an error causes DiskPart to exit
- with an error code.
+ NOERR Doar pentru scriere de fișiere script. Când apare o eroare,
+ programul DiskPart continuă să proceseze comenzi ca și când
+ eroarea nu ar fi apărut. Fără parametrul NOERR, o eroare
+ cauzează programul DiskPart să se închidă cu un cod de eroare.
- After the partition has been created, the focus automatically shifts to the
- new partition. Only one extended partition can be created per disk. This
- command fails if you attempt to create an extended partition within another
- extended partition. You must create an extended partition before you can
- create logical partitions.
+ După ce a fost creată partiția, marcajul se mută automat pe noua
+ partiție. Doar o singură partiție extinsă poate fi creată pe un disc.
+ Această comandă eșuează dacă încercați să creați o partiție extinsă
+ în altă partiție extinsă. Trebuie să creați o partiție extinsă
+ înainte de a crea partiții logice.
- A basic MBR disk must be selected for this operation to succeed.
+ Un disc MBR de bază trebuie să fie selectat pentru ca această operațiune
+ să aibă succes.
-Example:
+De exemplu:
CREATE PARTITION EXTENDED SIZE=1000
.
@@ -1343,38 +1347,40 @@ Example:
CREATE PARTITION LOGICAL SIZE=1000
.
Language=Romanian
- Creates a logical partition in an extended partition.
- Applies to master boot record (MBR) disks only.
+ Crează o partiție logică într-o partiție extinsă.
+ Se aplică doar la discurile cu Registrul principal de inițializare (MBR).
-Syntax: CREATE PARTITION LOGICAL [SIZE=<N>] [OFFSET=<N>] [ALIGN=<N>] [NOERR]
+Sintaxă: CREATE PARTITION LOGICAL [SIZE=<N>] [OFFSET=<N>] [ALIGN=<N>] [NOERR]
- SIZE=<N> The size of the partition in megabytes (MB). The partition is
- at least as big in bytes as the number specified by N. If you
- specify a size for the logical partition, it must be smaller
- than the extended partition. If no size is given, the partition
- continues until there is no more free space in the extended
- partition.
+ SIZE=<N> Mărimea partiției în megaocteți (Mo). Partiția e cel puțin
+ la fel de mare în octeți ca numărul specificat de N. Dacă
+ specificați o dimensiune pentru partiția logică, aceasta
+ trebuie să fie mai mică decât partiția logică. Dacă nu este
+ dată nicio mărime, partiția continuă până când nu mai este
+ spațiu liber pe partiția extinsă.
- OFFSET=<N> The offset, in kilobytes (KB), at which the partition is created.
- If no offset is given, the partition is placed in the first disk
- extent that is large enough to hold it.
+ OFFSET=<N> Decalajul, în kiloocteți (Ko), la care partiția e creată.
+ Dacă nu este dat niciun decalaj, partiția e plasată pe prima
+ expansiune a discului ce e suficient de mare ca să o țină.
- ALIGN=<N> Typically used with hardware RAID Logical Unit Number (LUN)
- arrays to improve performance. The partition offset will be
- a multiple of <N>. If the OFFSET parameter is specified, it
- will be rounded to the closest multiple of <N>.
+ ALIGN=<N> Folosită de obicei cu Numărul unității logice (LUN) RAID
+ a șirurilor de dispozitive pentru a îmbunătăți performanța.
+ Decalajul partiției va fi un multiplu a lui <N>. Dacă
+ parametrul OFFSET este specificat, va fi rotunjit la cel mai
+ apropiat multiplu a lui <N>.
+
+ NOERR Doar pentru scriere de fișiere script. Când apare o eroare,
+ programul DiskPart continuă să proceseze comenzi ca și când
+ eroarea nu ar fi apărut. Fără parametrul NOERR, o eroare
+ cauzează programul DiskPart să se închidă cu un cod de eroare.
- NOERR For scripting only. When an error is encountered, DiskPart
- continues to process commands as if the error did not occur.
- Without the NOERR parameter, an error causes DiskPart to exit
- with an error code.
+ După ce a fost creată partiția, marcajul se mută automat pe
+ noua partiție logică.
- After the partition has been created, the focus automatically shifts to the
- new logical partition.
+ Un disc MBR de bază trebuie să fie selectat pentru ca această operațiune
+ să reușească.
- A basic MBR disk must be selected for this operation to succeed.
-
-Example:
+De exemplu:
CREATE PARTITION LOGICAL SIZE=1000
.
@@ -1572,7 +1578,7 @@ Language=Portugese
<Add CREATE PARTITION MSR command help text here>
.
Language=Romanian
-<Add CREATE PARTITION MSR command help text here>
+<Adăugați aici textul de ajutor pentru comanda CREATE PARTITION MSR>
.
Language=Russian
<Add CREATE PARTITION MSR command help text here>
@@ -2037,105 +2043,111 @@ Example:
CREATE PARTITION PRIMARY SIZE=10000 ID=DE
.
Language=Romanian
- Creates a primary partition on the basic disk with focus.
+ Crează o partiție primară pe discul de bază în cauză.
-Syntax: CREATE PARTITION PRIMARY [SIZE=<N>] [OFFSET=<N>] [ID={<BYTE> | <GUID>}]
+Sintaxă: CREATE PARTITION PRIMARY [SIZE=<N>] [OFFSET=<N>] [ID={<BYTE> | <GUID>}]
[ALIGN=<N>] [NOERR]
- SIZE=<N> The size of the partition in megabytes (MB). If no size is
- given, the partition continues until there is no more
- unallocated space in the current region.
+ SIZE=<N> Mărimea partiției în megaocteți (Mo). Dacă nu e dată nicio
+ mărime, partiția continuă până când nu mai este spațiu nealocat
+ în regiunea curentă.
- OFFSET=<N> The offset, in kilobytes (KB), at which the partition is created.
- If no offset is given, the partition is placed in the first disk
- extent that is large enough to hold it.
+ OFFSET=<N> Decalajul, în kiloocteți (Ko), la care partiția este creată.
+ Dacă nu e dat niciun decalaj, partiția este plasată pe prima
+ expansiune de disc ce e suficient de mare ca să o țină.
ID={<BYTE> | <GUID>}
- Specifies the partition type.
+ Specifică tipul partiției.
- Intended for Original Equipment Manufacturer (OEM) use only.
+ Destinat numai pentru uzul producătorilor de echipamente
+ originale (OEM).
- For master boot record (MBR) disks, you can specify a partition
- type byte, in hexadecimal form, for the partition. If this
- parameter is not specified for an MBR disk, the command creates
- a partition of type 0x06 (specifies no file system is installed).
+ Pentru discurile cu Registrul principal de inițializare (MBR),
+ puteți specifica un octet, în format hexazecimal, pentru un tip
+ de partiție. Dacă acest parametru nu e specificat pentru
+ un disc MBR, comanda crează o partiție de tipul 0x06
+ (menționează că nu este niciun sistem de fișier instalat).
- LDM data partition:
+ Partiția de date LDM:
0x42
- Recovery partition:
+ Partiția de recuperare:
0x27
- Recognized OEM Ids:
+ Date de identificare (ID-uri) OEM:
0x12
0x84
0xDE
0xFE
0xA0
- For GUID partition table (GPT) disks you can specify a
- partition type GUID for the partition you want to create.
- Recognized GUIDs include:
+ Pentru discurile cu tabel de partiție GUID (GPT) puteți
+ specifica un tip de partiție GUID pentru partiția pe care vreți
+ să o creați. GUID-urile recunoscute includ:
- EFI System partition:
+ Partiția de sistem EFI:
c12a7328-f81f-11d2-ba4b-00a0c93ec93b
- Microsoft Reserved partition:
+ Partiția rezervată Microsoft:
e3c9e316-0b5c-4db8-817d-f92df00215ae
- Basic data partition:
+ Partiția de bază pentru date:
ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
- LDM Metadata partition on a dynamic disk:
+ Partiția de metadate LDM pe un disc dinamic:
5808c8aa-7e8f-42e0-85d2-e1e90434cfb3
- LDM Data partition on a dynamic disk:
+ Partiția de date LDM pe un disc dinamic:
af9b60a0-1431-4f62-bc68-3311714a69ad
- Recovery partition:
+ Partiția de recuperare:
de94bba4-06d1-4d40-a16a-bfd50179d6ac
- If this parameter is not specified for a GPT disk, the command
- creates a basic data partition.
-
- Any partition type byte or GUID can be specified with this
- parameter. DiskPart does not check the partition type for
- validity except to ensure that it is a byte in hexadecimal form
- or a GUID.
-
- Caution:
-
- Creating partitions with this parameter might cause your
- computer to fail or be unable to start up. Unless you are
- an OEM or an IT professional experienced with GPT disks, do
- not create partitions on GPT disks using this parameter.
- Instead, always use the CREATE PARTITION EFI command to
- create EFI System partitions, the CREATE PARTITION MSR
- command to create Microsoft Reserved partitions, and the
- CREATE PARTITION PRIMARY command without this parameter to
- create primary partitions on GPT disks.
-
- ALIGN=<N> Typically used with hardware RAID Logical Unit Number (LUN)
- arrays to improve performance. The partition offset will be
- a multiple of <N>. If the OFFSET parameter is specified, it
- will be rounded to the closest multiple of <N>.
-
- NOERR For scripting only. When an error is encountered, DiskPart
- continues to process commands as if the error did not occur.
- Without the NOERR parameter, an error causes DiskPart to exit
- with an error code.
-
- After you create the partition, the focus automatically shifts to the new
- partition. The partition does not receive a drive letter. You must use the
- assign command to assign a drive letter to the partition.
-
- A basic disk must be selected for this operation to succeed.
-
- If a partition type is not specified, the disk is uninitialized and disk
- size is greater than 2TB, it will be initialized to GPT.
-
-Example:
+ Dacă acest parametru nu este specificat pentru un disc GPT,
+ comanda crează o partiție de bază pentru date.
+
+ Orice octet care descrie tipul de partiție sau GUID poate fi
+ specificat cu acest parametru. DiskPart nu verifică tipul
+ partiției pentru validitate, cu excepția faptului că este
+ un octet cu valoare în format hexazecimal sau un GUID.
+
+ Atenție:
+
+ Crearea de partiții cu acest parametru poate cauza
+ calculatorului dumneavoastră să nu mai funcționeze bine sau
+ să nu mai poată porni. Dacă nu sunteți un OEM sau un
+ profesionist cu experiență în discuri GPT, nu creați
+ partiții pe discuri GPT folosind acest parametru.
+ În schimb, folosiți întotdeauna comanda
+ CREATE PARTITION EFI ca să creați partiții de sistem EFI,
+ comanda CREATE PARTITION MSR ca să creați partiții
+ rezervate Microsoft, și comanda CREATE PARTITION PRIMARY
+ fără acest parametru ca să creați partiții primare pe
+ discuri GPT.
+
+ ALIGN=<N> Folosită deobicei cu Numărul unității logice (LUN) RAID
+ a șirurilor de dispozitive pentru a îmbunătăți performanța.
+ Decalajul partiției va fi un multiplu a lui <N>. Dacă
+ parametrul OFFSET este specificat, va fi rotunjit la cel mai
+ apropiat multiplu a lui <N>.
+
+ NOERR Doar pentru scriere de fișiere script. Când apare o eroare,
+ programul DiskPart continuă să proceseze comenzi ca și când
+ eroarea nu ar fi apărut. Fără parametrul NOERR, o eroare
+ cauzează programul DiskPart să se închidă cu un cod de eroare.
+
+ După ce ați creat partiția, marcajul se mută automat pe noua partiție
+ logică. Partiția nu primește nicio literă de disc. Trebuie să folosiți
+ comanda de atribuire pentru a atribui partiției o literă de disc.
+
+ Un disc de bază trebuie să fie selectat pentru ca această operațiune
+ să reușească.
+
+ Dacă un tip de partiție nu e specificat, discul este neinițializat și
+ mărimea discului este mai mare de 2To, va fi inițializat cu GPT.
+
+De exemplu:
CREATE PARTITION PRIMARY SIZE=1000
CREATE PARTITION PRIMARY SIZE=128 ID=c12a7328-f81f-11d2-ba4b-00a0c93ec93b
@@ -2684,7 +2696,7 @@ Language=Portugese
<Add DELETE DISK command help text here>
.
Language=Romanian
-<Add DELETE DISK command help text here>
+<Adăugați aici textul de ajutor pentru comanda DELETE DISK>
.
Language=Russian
<Add DELETE DISK command help text here>
@@ -2816,28 +2828,29 @@ Example:
DELETE PARTITION
.
Language=Romanian
-Deletes the partition with focus.
-
-Syntax: DELETE PARTITION [NOERR] [OVERRIDE]
+Șterge partiția în cauză.
- NOERR For scripting only. When an error is encountered, DiskPart
- continues to process commands as if the error did not occur.
- Without the NOERR parameter, an error causes DiskPart to exit
- with an error code.
+Sintaxă: DELETE PARTITION [NOERR] [OVERRIDE]
- OVERRIDE Enables DiskPart to delete any partition regardless of type.
- Typically, DiskPart only permits you to delete known data
- partitions.
+ NOERR Doar pentru scriere de fișiere script. Când apare o eroare,
+ programul DiskPart continuă să proceseze comenzi ca și când
+ eroarea nu ar fi apărut. Fără parametrul NOERR, o eroare
+ cauzează programul DiskPart să se închidă cu un cod de eroare.
- You cannot delete the system partition, boot partition, or any partition
- that contains the active paging file or crash dump (memory dump) filed.
+ OVERRIDE Permite programului DiskPart să șteargă orice partiție,
+ indiferent de tipul său. De obicei, DiskPart vă permite doar
+ să ștergeți partițiile de date cunoscute.
- A partition must be selected for this operation to succeed.
+ Nu puteți șterge partiția de sistem, partiția de inițializare sau orice
+ altă partiție ce conține un fișier de paginație activ sau un registru
+ de colaps operațional (registru de memorie) solicitat.
- Partitions cannot be deleted from dynamic disks or created on dynamic
- disks.
+ O partiție trebuie selectată pentru ca acestă operațiune să reușească.
-Example:
+ Partițiile nu pot fi șterse de pe discurile dinamice sau create
+ pe discurile dinamice.
+
+De exemplu:
DELETE PARTITION
.
@@ -2987,7 +3000,7 @@ Language=Portugese
<Add DELETE VOLUME command help text here>
.
Language=Romanian
-<Add DELETE VOLUME command help text here>
+<Adăugați aici textul de ajutor pentru comanda DELETE VOLUME>
.
Language=Russian
<Add DELETE VOLUME command help text here>
@@ -3060,14 +3073,14 @@ Example:
DETAIL DISK
.
Language=Romanian
- Displays the properties of the selected disk and the list of volumes on
- the disk.
+ Afișează proprietățile discului selectat și listează volumele
+ pe disc.
-Syntax: DETAIL DISK
+Sintaxă: DETAIL DISK
- A disk must be selected for this operation to succeed.
+ Un disc trebuie să fie selectat pentru ca această operațiune să reușească.
-Example:
+De exemplu:
DETAIL DISK
.
@@ -3181,11 +3194,12 @@ Example:
DETAIL PARTITION
.
Language=Romanian
- Displays the properties for the selected partition.
+ Afișează proprietățile pentru partiția selectată.
-Syntax: DETAIL PARTITION
+Sintaxă: DETAIL PARTITION
- A partition must be selected for this operation to succeed.
+ O partiție trebuie să fie selectată pentru ca această operațiune
+ să reușească.
Example:
@@ -3301,14 +3315,14 @@ Example:
DETAIL VOLUME
.
Language=Romanian
- Displays the properties for the selected volume and the list of disks on
- which the volume resides.
+ Afișează proprietățile pentru volumul selectat și listează discurile
+ pe care aparține volumul.
-Syntax: DETAIL VOLUME
+Sintaxă: DETAIL VOLUME
- A volume must be selected for this operation to succeed.
+ Un volum trebuie să fie selectat pentru ca această operațiune să reușească.
-Example:
+De exemplu:
DETAIL VOLUME
.
@@ -3390,7 +3404,7 @@ Language=Portugese
<Add DETACH command help text here>
.
Language=Romanian
-<Add DETACH command help text here>
+<Adăugați aici textul de ajutor pentru comanda DETACH>
.
Language=Russian
<Add DETACH command help text here>
@@ -3450,11 +3464,11 @@ Example:
EXIT
.
Language=Romanian
- Exits the DiskPart command interpreter.
+ Iese din interpretorul de comenzi al programului DiskPart.
-Syntax: EXIT
+Sintaxă: EXIT
-Example:
+De exemplu:
EXIT
.
@@ -3522,7 +3536,7 @@ Language=Portugese
<Add EXPAND command help text here>
.
Language=Romanian
-<Add EXPAND command help text here>
+<Adăugați aici textul de ajutor pentru comanda EXPAND>
.
Language=Russian
<Add EXPAND command help text here>
@@ -3558,7 +3572,7 @@ Language=Portugese
<Add EXTEND command help text here>
.
Language=Romanian
-<Add EXTEND command help text here>
+<Adăugați aici textul de ajutor pentru comanda EXTEND>
.
Language=Russian
<Add EXTEND command help text here>
@@ -3632,14 +3646,15 @@ Example:
FILESYSTEMS
.
Language=Romanian
- Displays information about the current file system for the selected
- volume, and the supported file systems for formatting the volume.
+ Afișează informații despre sistemul actual de fișiere pentru volumul
+ selectat și pentru sistemele de fișiere suportate pentru formatarea
+ volumului.
-Syntax: FILESYSTEMS
+Sintaxă: FILESYSTEMS
- A volume must be selected for this operation to succeed.
+ Un volum trebuie să fie selectat pentru ca această operațiune să reușească.
-Example:
+De exemplu:
FILESYSTEMS
.
@@ -3979,68 +3994,70 @@ Examples:
FORMAT RECOMMENDED OVERRIDE
.
Language=Romanian
- Formats the specified volume for use with ReactOS.
+ Formatează volumul specificat pentru folosire cu ReactOS.
-Syntax: FORMAT [[FS=<FS>] [REVISION=<X.XX>] | RECOMMENDED] [LABEL=<"label">]
+Sintaxă: FORMAT [[FS=<FS>] [REVISION=<X.XX>] | RECOMMENDED] [LABEL=<"label">]
[UNIT=<N>] [QUICK] [COMPRESS] [OVERRIDE] [DUPLICATE] [NOWAIT]
[NOERR]
- FS=<FS> Specifies the type of file system. If no file system is given,
- the default file system displayed by the FILESYSTEMS command is
- used.
+ FS=<FS> Specifică tipul sistemului de fișiere. Dacă nu e dat niciun
+ sistem de fișiere, este folosit sistemul de fișiere implicit
+ afișat de comanda FILESYSTEMS.
REVISION=<X.XX>
- Specifies the file system revision (if applicable).
+ Specifică revizia sistemului de fișiere (dacă este aplicabil).
- RECOMMENDED If specified, use the recommended file system and revision
- instead of the default if a recommendation exists. The
- recommended file system (if one exists) is displayed by the
- FILESYSTEMS command.
-
- LABEL=<"label">
+ RECOMMENDED Dacă este specificat, folosiți sistemul de fișiere recomandat
+ și revizia în locul celui implicit dacă există o
+ recomandare. Sistemul de fișiere recomandat (dacă există unul)
+ este afișat de comanda FILESYSTEMS.
- Specifies the volume label.
-
- UNIT=<N> Overrides the default allocation unit size. Default settings
- are strongly recommended for general use. The default
- allocation unit size for a particular file system is displayed
- by the FILESYSTEMS command.
+ LABEL=<"etichetă">
- NTFS compression is not supported for allocation unit sizes
- above 4096.
+ Specifică eticheta volumului.
- QUICK Performs a quick format.
+ UNIT=<N> Ignoră dimensiunea implicită a unității de alocare. Setările
+ implicite sunt recomandate cu tărie pentru uz general.
+ Dimensiunea implicită a unității de alocare pentru un anumit
+ sistem de fișiere este afișată de comanda FILESYSTEMS.
- COMPRESS NTFS only: Files created on the new volume will be compressed
- by default.
+ Comprimarea NTFS nu este acceptată pentru dimensiunile
+ unităților de alocare mai mari de 4096.
- OVERRIDE Forces the file system to dismount first if necessary. All
- opened handles to the volume would no longer be valid.
+ QUICK Efectuează o formatare rapidă.
- DUPLICATE UDF Only: This flag applies to UDF format, version 2.5 or
- higher.
- This flag instructs the format operation to duplicate the file
- system meta-data to a second set of sectors on the disk. The
- duplicate meta-data is used by applications, for example repair
- or recovery applications. If the primary meta-data sectors are
- found to be corrupted, the file system meta-data will be read
- from the duplicate sectors.
+ COMPRESS Numai pentru formatul NTFS: Fișierele create pe noul volum
+ vor fi comprimate în mod implicit.
+ OVERRIDE Forțează mai întâi demontarea sistemului de fișiere, dacă e
+ necesar. Toate identificatoarele de gestiune deschise ale
+ volumului nu ar mai fi valabile.
- NOWAIT Forces the command to return immediately while the format
- process is still in progress. If NOWAIT is not specified,
- DiskPart will display format progress in percentage.
+ DUPLICATE Numai pentru formatul UDF: Această etichetă e aplicată
+ formatului UDF, versiunea 2.5 sau mai nouă. Această etichetă
+ intruiește operațiunea de formatare să dubleze metadatele
+ sistemului de fișiere la cel de al doilea set de sectoare
+ de pe disc. Metadatele dublate sunt folosite de aplicații,
+ de exemplu de utilitare de reparare și de recuperare. Dacă
+ sectoarele primare de metadate sunt găsite ca și corupte,
+ metadatele sistemului de fișiere vor fi citite de sectoarele
+ duplicate.
- NOERR For scripting only. When an error is encountered, DiskPart
- continues to process commands as if the error did not occur.
- Without the NOERR parameter, an error causes DiskPart to exit
- with an error code.
+ NOWAIT Forțează comanda să se întoarcă imediat atât timp cât procesul
+ de formatare este încă în curs. Dacă NOWAIT nu este
+ specificat, programul DiskPart va afișa progesul formatării
+ în procente.
+
+ NOERR Doar pentru scriere de fișiere script. Când apare o eroare,
+ programul DiskPart continuă să proceseze comenzi ca și când
+ eroarea nu ar fi apărut. Fără parametrul NOERR, o eroare
+ cauzează programul DiskPart să se închidă cu un cod de eroare.
- A volume must be selected for this operation to succeed.
+ Un volum trebuie să fie selectat pentru ca această operațiune să reușească.
-Examples:
+De exemplu:
- FORMAT FS=NTFS LABEL="New Volume" QUICK COMPRESS
+ FORMAT FS=NTFS LABEL="Volum nou" QUICK COMPRESS
FORMAT RECOMMENDED OVERRIDE
.
Language=Russian
@@ -4377,7 +4394,7 @@ Language=Portugese
<Add GPT command help text here>
.
Language=Romanian
-<Add GPT command help text here>
+<Adăugați aici textul de ajutor pentru comanda GPT>
.
Language=Russian
<Add GPT command help text here>
@@ -4465,16 +4482,17 @@ Example:
HELP CREATE PARTITION PRIMARY
.
Language=Romanian
- Displays a list of the available commands or detailed help information for a
- specified command.
+ Afișează o listă a comenzilor disponibile sau informații detaliate
+ de ajutor pentru o comandă specificată.
-Syntax: HELP [<COMMAND>]
+Sintaxă: HELP [<COMMAND>]
- <COMMAND> The command for which to display detail help.
+ <COMMAND> Comanda pentru care se afișează ajutorul detaliat.
- If no command is specified, HELP will display all possible commands.
+ Dacă nu este specificată nicio comandă, comanda HELP va afișa
+ toate comenzile posibile.
-Example:
+De exemplu:
HELP
HELP CREATE PARTITION PRIMARY
@@ -4572,7 +4590,7 @@ Language=Portugese
<Add IMPORT command help text here>
.
Language=Romanian
-<Add IMPORT command help text here>
+<Adăugați aici textul de ajutor pentru comanda IMPORT>
.
Language=Russian
<Add IMPORT command help text here>
@@ -4692,25 +4710,27 @@ Example:
INACTIVE
.
Language=Romanian
- On disks with master boot record (MBR) disk formatting, marks
- the partition with focus as inactive.
+ Pe discurile cu formatare Registrul principal de inițializare (MBR),
+ marchează partiția în cauză ca inactivă.
-Syntax: INACTIVE
+Sintaxă: INACTIVE
- The computer may start from the next option specified in the BIOS such as a
- CD-ROM drive or a Pre-Boot eXecution Environment (PXE)-based boot
- environment (such as Remote Installation Services (RIS)) when you restart
- the computer.
+ Calculatorul poate începe cu următoarea opțiune specificată în BIOS cum ar
+ fi, un mediu de inițializare pe un disc CD-ROM sau pe un Mediu de execuție
+ de preinițializare (PXE) (cum ar fi, Servicii de instalare de la distanță
+ (RIS)) atunci când vă reporniți calculatorul.
- A partition must be selected for this operation to succeed.
+ O partiție trebuie să fie selectată pentru ca această operațiune
+ să reușească.
- Caution:
+ Atenție:
- Your computer might not start without an active partition. Do not mark
- a system or boot partition as inactive unless you are an experienced
- user with a thorough understanding of ReactOS storage management.
+ Calculatorul dumneavoastră ar putea să nu pornească fără o partiție
+ activă. Nu marcați o partiție de sistem sau de inițializare ca inactivă
+ dacă nu sunteți un utilizator experimentat cu o înțelegere aprofundată
+ a gestionării stocării ReactOS.
-Example:
+De exemplu:
INACTIVE
.
@@ -4939,27 +4959,26 @@ Example:
LIST DISK
.
Language=Romanian
- Displays a list of disks.
+ Afișează o listă de discuri.
-Syntax: LIST DISK
+Sintaxă: LIST DISK
- Displays a list of disks and information about them, such as their
- size, amount of available free space, whether the disk is a basic
- or dynamic disk, and whether the disk uses the master boot record
- (MBR) or GUID partition table (GPT) partition style. The disk marked
- with an asterisk (*) has focus.
+ Afișează o listă de discuri și de informații despre ele, cum ar fi
+ mărimea lor, cantitatea de spațiu liber disponibil, dacă discul este un
+ disc static sau un disc dinamic și dacă discul folosește stilul de
+ partiționare Registrul principal de inițializare (MBR) sau tabelul de
+ partiționare GUID (GPT). Discul marcat cu un asterisc (*) are marcaj.
- Note that the FREE column does not display the total amount of free
- space on the disk, but rather the amount of usable free space left
- on the disk. For example, if you have a 10GB disk with 4 primary
- partitions covering 5GB, there is no usable free space left (no
- more partitions may be created). Another example would be you have
- a 10GB disk with 3 primary partitions and an extended partition
- covering 8GB. The exended partition is of size 3GB with one logical
- drive of size 2GB. The disk will show only 1GB as free - the
- 1GB of free space in the extended partition.
+ Rețineți că coloana FREE nu afișează cantitatea totală de spațiu liber
+ pe disc, dar mai degrabă cantitatea de spațiu liber utilizabil rămas pe
+ disc. De exemplu, dacă aveți un disc de 10Go cu 4 partiții primare care
+ acoperă 5Go, nu este spațiu liber utilizabil rămas (nu mai pot fi create
+ alte partiții). Alt exemplu poate fi că aveți un disc de 10Go cu 3 partiții
+ primare și o partiție extinsă care acoperă 8Go. Partiția există are mărimea
+ de 3GB cu un disc logic demărime de 2Go. Discul va arăta numai 1Go ca
+ spațiu liber - spațiu liber de 1Go în partiția extinsă.
-Example:
+De exemplu:
LIST DISK
.
@@ -5154,17 +5173,18 @@ Example:
LIST PARTITION
.
Language=Romanian
- Displays a list of partitions in the partition table for the selected disk.
+ Afișează o listă de partiții în tabelul de partiționare pentru discul
+ selectat.
-Syntax: LIST PARTITION
+Sintaxă: LIST PARTITION
- On dynamic disks, the partitions do not neccessarily correspond to the
- dynamic volumes on the disk. Partitions may not be created or deleted
- on dynamic disks.
+ Pe discurile dinamice, partițiile nu corespund în mod necesar, volumelor
+ dinamice de pe disc. Partițiile nu pot fi create sau șterse pe discurile
+ dinamice.
- A disk must be selected for this operation to succeed.
+ Un disc trebuie să fie selectat pentru ca această operațiune să reușească.
-Example:
+De exemplu:
LIST PARTITION
.
@@ -5289,12 +5309,12 @@ Example:
LIST VOLUME
.
Language=Romanian
- Displays a list of basic and dynamic volumes which are installed on the local
- machine.
+ Afișează o listă a volumelor de bază sau dinamice ce sunt instalate în
+ calculatorul local.
+
+Sintaxă: LIST VOLUME
-Syntax: LIST VOLUME
-
-Example:
+De exemplu:
LIST VOLUME
.
@@ -5366,7 +5386,7 @@ Language=Portugese
<Add LIST VDISK command help text here>
.
Language=Romanian
-<Add LIST VDISK command help text here>
+<Adăugați aici textul de ajutor pentru comanda LIST VDISK>
.
Language=Russian
<Add LIST VDISK command help text here>
@@ -5402,7 +5422,7 @@ Language=Portugese
<Add MERGE command help text here>
.
Language=Romanian
-<Add MERGE command help text here>
+<Adăugați aici textul de ajutor pentru comanda MERGE>
.
Language=Russian
<Add MERGE command help text here>
@@ -5438,7 +5458,7 @@ Language=Portugese
<Add OFFLINE command help text here>
.
Language=Romanian
-<Add OFFLINE command help text here>
+<Adăugați aici textul de ajutor pentru comanda OFFLINE>
.
Language=Russian
<Add OFFLINE command help text here>
@@ -5474,7 +5494,7 @@ Language=Portugese
<Add ONLINE command help text here>
.
Language=Romanian
-<Add ONLINE command help text here>
+<Adăugați aici textul de ajutor pentru comanda ONLINE>
.
Language=Russian
<Add ONLINE command help text here>
@@ -5510,7 +5530,7 @@ Language=Portugese
<Add RECOVER command help text here>
.
Language=Romanian
-<Add RECOVER command help text here>
+<Adăugați aici textul de ajutor pentru comanda RECOVER>
.
Language=Russian
<Add RECOVER command help text here>
@@ -5610,16 +5630,16 @@ Example:
ASSIGN f:
.
Language=Romanian
- Provides a way to add comments to a script.
+ Furnizează un mod de a adăuga comentarii la un script.
-Syntax: REM
+Sintaxă: REM
-Example:
+De exemplu:
- In this example script, REM is used to provide a comment about what the
- script does.
+ În acest script exemplificat, comanda REM este folosită ca să furnizeze
+ un comentariu despre ce face scriptul.
- REM These commands set up 3 drives.
+ REM Aceste comenzi configurează 3 discuri.
CREATE PARTITION PRIMARY SIZE=2048
ASSIGN d:
CREATE PARTITION EXTEND
@@ -5741,7 +5761,7 @@ Language=Portugese
<Add REMOVE command help text here>
.
Language=Romanian
-<Add REMOVE command help text here>
+<Adăugați aici textul de ajutor pentru comanda REMOVE>
.
Language=Russian
<Add REMOVE command help text here>
@@ -5777,7 +5797,7 @@ Language=Portugese
<Add REPAIR command help text here>
.
Language=Romanian
-<Add REPAIR command help text here>
+<Adăugați aici textul de ajutor pentru comanda REPAIR>
.
Language=Russian
<Add REPAIR command help text here>
@@ -5838,11 +5858,11 @@ Example:
RESCAN
.
Language=Romanian
- Locates new disks that may have been added to the computer.
+ Localizează noile discuri ce pot fi adăugate la calculator.
-Syntax: RESCAN
+Sintaxă: RESCAN
-Example:
+De exemplu:
RESCAN
.
@@ -5910,7 +5930,7 @@ Language=Portugese
<Add RETAIN command help text here>
.
Language=Romanian
-<Add RETAIN command help text here>
+<Adăugați aici textul de ajutor pentru comanda RETAIN>
.
Language=Russian
<Add RETAIN command help text here>
@@ -5946,7 +5966,7 @@ Language=Portugese
<Add SAN command help text here>
.
Language=Romanian
-<Add SAN command help text here>
+<Adăugați aici textul de ajutor pentru comanda SAN>
.
Language=Russian
<Add SAN command help text here>
@@ -6143,40 +6163,40 @@ Example:
SELECT DISK=PCIROOT(0)#PCI(0100)#ATA(C00T00L01)
.
Language=Romanian
- Selects the specified disk and shifts the focus to it.
+ Selectează discul specificat și mută marcajul pe el.
-Syntax: SELECT DISK=<N>
+Sintaxă: SELECT DISK=<N>
SELECT DISK=SYSTEM
SELECT DISK=NEXT
- SELECT DISK=<Path>
+ SELECT DISK=<Cale>
DISK=<N>
- The DiskPart disk index number of the disk to receive
- focus.
+ Numărul indexului discului pentru programul DiskPart care
+ urmează să primească marcajul.
- DISK=<Path>
- The location path of the disk to receive focus.
+ DISK=<Cale>
+ Calea locației discului care urmează să primească marcajul.
DISK=SYSTEM
- On BIOS machines, BIOS disk 0 will receive focus.
- On EFI machines, the disk containing the ESP partition
- used for the current boot will receive focus. On EFI
- machines, if there is no ESP, or there is more than
- one ESP present, or the machine is booted from Windows PE,
- the command will fail.
+ La calculatoarele cu BIOS, discul 0 din BIOS va fi marcat.
+ La calculatoarele EFI, discul care conține partiția ESP
+ folosită pentru inițializarea curentă va primi marcaj.
+ La calculatoarele EFI, dacă nu este ESP sau este prezent
+ mai mult decât un ESP sau calculatorul este inițializat din
+ Windows PE, comanda va eșua.
DISK=NEXT
- Once a disk is selected, this command is used to iterate
- over all disks in the disk list. The next disk in the list
- will receive focus. If the next disk is the start of the
- enumeration, the command will fail and no disk will have
- focus.
+ Odată ce discul e selectat, această comandă este folosită
+ pentru a fi aplicată fiecărui disc din lista de discuri.
+ Următorul disc din listă va primi marcaj. Dacă următorul
+ disc este începutul enumerării, comanda va eșua și niciun disc
+ nu va trebui să fie marcat.
- If no options are specified, the select command lists the disk that
- currently has the focus. You can view the DiskPart index numbers
- for all disks on the computer by using the LIST DISK command.
+ Dacă nicio opțiune nu este specificată, comanda SELECT va lista discul
+ care este marcat în prezent. Puteți vizualiza numerele de index pentru
+ toate discurile din calculator folosind comanda LIST DISK.
-Example:
+De exemplu:
SELECT DISK=1
SELECT DISK=SYSTEM
@@ -6477,23 +6497,20 @@ Example:
SELECT PARTITION=1
.
Language=Romanian
- Selects the specified partition and shifts the focus to it.
+ Selectează partiția specificată și mută marcajul pe ea.
-Syntax: SELECT PARTITION=<N>
+Sintaxă: SELECT PARTITION=<N>
PARTITION=<N>
- The number of the partition to receive the focus.
+ Numărul partiției ce urmează să primească marcajul.
- If no partition is specified, the select command lists the current
- partition with focus. You can specify the partition by its number. You can
- view the numbers of all partitions on the current disk by using the list
- partition command.
-
- You must first select a disk using the DiskPart select disk command before
- you can select a partition.
-
-Example:
+ Dacă nicio partiție nu este specificată, comanda SELECT va lista partiția
+ marcată în prezent. Puteți specifica partiția prin numărul său. Puteți
+ vizualiza numerele tuturor partițiilor de pe discul actual folosind
+ comanda LIST PARTITION.
+
+De exemplu:
SELECT PARTITION=1
.
@@ -6699,22 +6716,23 @@ Example:
SELECT VOLUME=C:\\MountH
.
Language=Romanian
- Selects the specified volume and shifts the focus to it.
+ Selectează volumul specificat și mută marcajul pe el.
-Syntax: SELECT VOLUME={<N> | <D>}
+Sintaxă: SELECT VOLUME={<N> | <D>}
- VOLUME=<N> The number of the volume to receive the focus.
+ VOLUME=<N> Numărul volumului care urmează să primească marcajul.
- VOLUME=<D> The drive letter or mounted folder path of the volume
- to receive the focus.
+ VOLUME=<D> Litera discului sau calea dosarului montat al volumului
+ ce urmează să primească marcajul.
- If no volume is specified, the select command lists the current volume with
- focus. You can specify the volume by number, drive letter, or mounted folder
- path. On a basic disk, selecting a volume also gives the corresponding
- partition focus. You can view the numbers of all volumes on the computer by
- using the list volume command.
+ Dacă niciun volum nu e specificat, comanda SELECT listează volumul actual
+ cu marcaj. Puteți specifica volumul după număr, după litera discului sau
+ după calea dosarului montat. Pe un disc de bază, selectarea unui volum
+ oferă de asemenea, marcajul corespunzător pe partiție. Puteți
+ vizualiza numărul tuturor volumelor din calculator folosind comanda
+ LIST VOLUME.
-Example:
+De exemplu:
SELECT VOLUME=1
SELECT VOLUME=C
@@ -6847,7 +6865,7 @@ Language=Portugese
<Add SELECT VDISK command help text here>
.
Language=Romanian
-<Add SELECT VDISK command help text here>
+<Adăugați aici textul de ajutor pentru comanda SELECT VDISK>
.
Language=Russian
<Add SELECT VDISK command help text here>
@@ -7219,84 +7237,88 @@ Example:
SET ID=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
.
Language=Romanian
- Changes the partition type field for the partition with focus.
+ Schimbă registrul tipului partiției pentru partiția în cauză.
-Syntax: SET ID={<BYTE> | <GUID>} [OVERRIDE] [NOERR]
+Sintaxă: SET ID={<BYTE> | <GUID>} [OVERRIDE] [NOERR]
ID={<BYTE> | <GUID>}
- Specifies the new partition type.
- For master boot record (MBR) disks, you can specify a partition
- type byte, in hexadecimal form, for the partition. Any
- partition type byte can be specified with this parameter except
- for type 0x42 (LDM partition). Note that the leading '0x' is
- omitted when specifying the hexadecimal partition type.
-
- For GUID partition table (GPT) disks you can specify a
- partition type GUID for the partition. Recognized GUIDs
- include:
-
- EFI System partition:
+ Specifică noul tip al partiției.
+ Pentru discurile cu Registrul principal de inițializare (MBR),
+ puteți speciifica puteți specifica un octet, în format
+ hexazecimal, pentru un tip de partiție. Orice octet care
+ descrie tipul de partiție poate fi specificată cu acest
+ parametru, exceptând pentru tipul 0x42 (partiție LDM). Rețineți
+ că primul '0x' când este specificat în hexazecimal un tip de
+ partiție.
+
+ Pentru discurile cu tabelul de partiție GUID (GPT) puteți
+ specifica un tip de partiție GUID pentru partiția pe care vreți
+ să o creați. GUID-urile recunoscute includ:
+
+ Partiția de sistem EFI:
c12a7328-f81f-11d2-ba4b-00a0c93ec93b
- Basic data partition:
+ Partiția de bază pentru date:
ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
- Any partition type GUID can be specified with this parameter
- except for the following:
+ Orice partiție de tip GUID poate fi specificată cu acest
+ parametru exceptând următoarele:
- Microsoft Reserved partition:
+ Partiția rezervată Microsoft:
e3c9e316-0b5c-4db8-817d-f92df00215a
- LDM Metadata partition on a dynamic disk:
+ Partiția de metadate LDM pe un disc dinamic:
5808c8aa-7e8f-42e0-85d2-e1e90434cfb3
- LDM Data partition on a dynamic disk:
+ Partiția de date LDM pe un disc dinamic:
af9b60a0-1431-4f62-bc68-3311714a69ad
- Cluster Metadata partition:
+ Partiția de metadate a grupului:
db97dba9-0840-4bae-97f0-ffb9a327c7e1
- Other than the limitations mentioned, DiskPart otherwise does
- not check the partition type for validity except to ensure that
- it is a byte in hexadecimal form or a GUID.
-
- OVERRIDE Enables DiskPart to force the file system on the volume to
- dismount before changing the partition type. When changing
- the partition type, DiskPart will attempt to lock and dismount
- the file system on the volume. If this parameter is not specified,
- and the call to lock the file system fails, (because some other
- application has an open handle to the volume), the entire
- operation will fail. When this parameter is specified, the
- dismount is forced even if the call to lock the file system
- fails. When a file system is dismounted, all opened handles to
- the volume will become invalid.
-
- NOERR For scripting only. When an error is encountered, DiskPart
- continues to process commands as if the error did not occur.
- Without the NOERR parameter, an error causes DiskPart to exit
- with an error code.
-
- Intended for Original Equipment Manufacturer (OEM) use only.
-
- A partition must be selected for this operation to succeed.
-
- Caution:
-
- Changing partition type fields with this parameter might cause your
- computer to fail or be unable to start up. Unless you are an OEM or an
- IT professional experienced with GPT disks, do not change partition
- type fields on GPT disks using this parameter. Instead, always use the
- CREATE PARTITION EFI command to create EFI System partitions, the
- CREATE PARTITION MSR command to create Microsoft Reserved partitions,
- and the CREATE PARTITION PRIMARY command without the ID parameter to
- create primary partitions on GPT disks.
-
- This command does not work on dynamic disks nor on Microsoft Reserved
- partitions.
-
-Example:
+ În afară de limitările menționate, DiskPart nu verifică
+ valabilitatea tipului de partiție decât pentru a se asigura că
+ este un octet în formă hexazecimală sau un GUID.
+
+ OVERRIDE Activează DiskPart pentru a forța sistemul de fișiere pe volum
+ să demonteze tipul de partiție înainte de a-l schimba. Când se
+ schimbă tipul de partiție, DiskPart va încerca să blocheze și
+ să demonteze sistemul de fișiere pe volum. Dacă acest parametru
+ nu este specificat și apelarea blocării sistemului de fișiere
+ eșuează, (deoarece alte câteva aplicații au un identificator
+ de gestiune deschis pentru volum), întreaga operațiune va eșua.
+ Când acest parametru este specificat, demontarea e forțată
+ chiar dacă apelarea blocării sistemului de fișiere eșuează.
+ Când un sistem de fișiere e demontat, toate identificatoarele
+ de gestiune deschise ale volumului vor deveni nevalide.
+
+ NOERR Doar pentru scriere de fișiere script. Când apare o eroare,
+ programul DiskPart continuă să proceseze comenzi ca și când
+ eroarea nu ar fi apărut. Fără parametrul NOERR, o eroare
+ cauzează programul DiskPart să se închidă cu un cod de eroare.
+
+ Destinat numai pentru utilizarea producătorilor de echipamente originale
+ (OEM).
+
+ O partiție trebuie selectată pentru ca acestă operațiune să reușească.
+
+ Atenție:
+
+ Crearea de partiții cu acest parametru poate cauza calculatorului
+ dumneavoastră să eșueaze sau să nu mai poată porni. Dacă nu sunteți un
+ OEM sau un profesionist cu experiență în discuri GPT, nu creați
+ partiții pe discuri GPT folosind acest parametru. În schimb, folosiți
+ întotdeauna comanda CREATE PARTITION EFI ca să creați partiții de
+ sistem EFI, comanda CREATE PARTITION MSR ca să creați partiții
+ rezervate Microsoft, și comanda CREATE PARTITION PRIMARY fără acest
+ parametru ca să creați partiții primare pe discuri GPT.
+
+ Această comandă nu funcționează nici pe discuri dinamice, nici pe
+ Partiții rezervate Microsoft.
+
+De exemplu:
SET ID=07 OVERRIDE
SET ID=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
.
@@ -7719,7 +7741,7 @@ Language=Portugese
<Add SHRINK command help text here>
.
Language=Romanian
-<Add SHRINK command help text here>
+<Adăugați aici textul de ajutor pentru comanda SHRINK>
.
Language=Russian
<Add SHRINK command help text here>
@@ -7856,27 +7878,27 @@ Example:
UNIQUEID DISK ID=baf784e7-6bbd-4cfb-aaac-e86c96e166ee
.
Language=Romanian
- Displays or sets the GUID partition table (GPT) identifier or master boot
- record (MBR) signature for the disk with focus.
+ Afișează sau setează identificatorul tabelului de partiție GUID (GPT) sau
+ semnătura Registrului principal de inițializare (MBR) pentru discul
+ în cauză.
-Syntax: UNIQUEID DISK [ID={<DWORD> | <GUID>}] [NOERR]
+Sintaxă: UNIQUEID DISK [ID={<DWORD> | <GUID>}] [NOERR]
ID={<DWORD> | <GUID>}
- For MBR disks, you can specify a four-byte (DWORD) value in
- hexadecimal form for the signature.
+ Pentru discurile MBR, puteți specifica o valoare de patru
+ octeți (DWORD) formă hexazecimală pentru semnătură.
- For GPT disks, specify a GUID for the identifier.
+ Pentru discurile GPT, specificați un GUID pentru identificator.
- NOERR For scripting only. When an error is encountered, DiskPart
- continues to process commands as if the error did not occur.
- Without the NOERR parameter, an error causes DiskPart to exit
- with an error code.
+ NOERR Doar pentru scriere de fișiere script. Când apare o eroare,
+ programul DiskPart continuă să proceseze comenzi ca și când
+ eroarea nu ar fi apărut. Fără parametrul NOERR, o eroare
+ cauzează programul DiskPart să se închidă cu un cod de eroare.
- A disk must be selected for this operation to succeed. This command works
- on basic and dynamic disks.
+ Un disc trebuie să fie selectat pentru ca această operațiune să reușească.
-Example:
+De exemplu:
UNIQUEID DISK
UNIQUEID DISK ID=5f1b2c36
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=cad780e17caddbe7660d9…
commit cad780e17caddbe7660d95755be5c145c4ada98b
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Wed Jul 5 20:31:23 2023 +0200
Commit: unknown <george.bisoc(a)reactos.org>
CommitDate: Tue Aug 22 17:54:18 2023 +0200
[SDK:RTL] Fix the ACE revision check in RtlpAddKnownObjectAce
Object ACEs are supported starting from Revision 4, the current code checks
if the revision is above Revision 4. An Object ACE has to be strictly set on that revision,
whereas Object ACLs can be of any revision starting from ACL_REVISION4.
---
sdk/lib/rtl/acl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdk/lib/rtl/acl.c b/sdk/lib/rtl/acl.c
index afe41d0bcdb..efe7d331a57 100644
--- a/sdk/lib/rtl/acl.c
+++ b/sdk/lib/rtl/acl.c
@@ -173,7 +173,7 @@ RtlpAddKnownObjectAce(IN PACL Acl,
if (!RtlValidSid(Sid)) return STATUS_INVALID_SID;
/* Check the validity of the revision */
- if ((Acl->AclRevision > ACL_REVISION4) || (Revision > ACL_REVISION4))
+ if ((Acl->AclRevision > ACL_REVISION4) || (Revision != ACL_REVISION4))
{
return STATUS_REVISION_MISMATCH;
}
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a42f642ea117ffc27a378…
commit a42f642ea117ffc27a378c4938b555dfdd461a45
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Wed Jun 21 17:55:19 2023 +0200
Commit: unknown <george.bisoc(a)reactos.org>
CommitDate: Tue Aug 22 17:54:17 2023 +0200
[NTOS:SE] Implement access security checks by type
- Implement SepDenyAccessObjectTypeResultList, SepAllowAccessObjectTypeResultList,
SepDenyAccessObjectTypeList and SepAllowAccessObjectTypeList. These routines will
be used to grant or deny access to sub-objects of an object in the list.
- Refactor SepAnalyzeAcesFromDacl and SepAccessCheck to accomodate the newly
implemented access check by type mechanism.
- SepAccessCheck will now be SepAccessCheckWorker, a worker helper function that further
abstracts the access check mechanism in the kernel. Whereas the SepAccessCheck name will be
used as a centralized function used by the access check NT system calls.
- Deprecate SepGetSDOwner and SepGetSDGroup in favor of SepGetOwnerFromDescriptor and
SepGetGroupFromDescriptor. The former functions were buggy as they might potentially
return garbage data if either the owner or group were passed as NULL to a security
descriptor, hence a second chance exception fault. This was caught when writing tests
for NtAccessCheckByType.
- Shorten the debug prints by removing the name of the functions, the person who reads
the debugger output has to look at the source code anyway.
---
ntoskrnl/se/accesschk.c | 1928 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 1409 insertions(+), 519 deletions(-)
diff --git a/ntoskrnl/se/accesschk.c b/ntoskrnl/se/accesschk.c
index 690f7c029e7..d63e07429e8 100644
--- a/ntoskrnl/se/accesschk.c
+++ b/ntoskrnl/se/accesschk.c
@@ -15,6 +15,371 @@
/* PRIVATE FUNCTIONS **********************************************************/
+/**
+ * @brief
+ * Denies access of a target object and the children objects
+ * in an object type list.
+ *
+ * @param[in,out] ObjectTypeList
+ * A pointer to an object type list where access is to be
+ * denied for the target object and its children in the
+ * hierarchy list.
+ *
+ * @param[in] ObjectTypeListLength
+ * The length of the object type list. This length represents
+ * the number of object elements in the list.
+ *
+ * @param[in] AccessMask
+ * The access mask right that is to be denied for the object.
+ *
+ * @param[in] ObjectTypeGuid
+ * A pointer to a object type GUID, that identifies the object.
+ * This GUID is used to search for the target object in the list.
+ * If this parameter is set to NULL, the function will deny access
+ * starting from the object itself in the list (aka the root).
+ */
+static
+VOID
+SepDenyAccessObjectTypeResultList(
+ _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ ACCESS_MASK AccessMask,
+ _In_opt_ PGUID ObjectTypeGuid)
+{
+ ULONG ObjectTypeIndex;
+ ULONG ReturnedObjectIndex;
+ USHORT Level;
+
+ PAGED_CODE();
+
+ DPRINT("Access rights 0x%08lx\n", AccessMask);
+
+ /*
+ * The object type of interest is the one that was supplied
+ * by the creator who made the ACE. If the object type was
+ * not supplied then we have no clear indication from where
+ * shall we start updating the access rights of objects on
+ * this list, so we have to begin from the root (aka the
+ * object itself).
+ */
+ if (!ObjectTypeGuid)
+ {
+ DPRINT("No object type provided, updating access rights from root\n");
+ ReturnedObjectIndex = 0;
+ goto LoopAndUpdateRightsObjects;
+ }
+
+ /* Check if that object exists in the list */
+ if (SepObjectTypeGuidInList(ObjectTypeList,
+ ObjectTypeListLength,
+ ObjectTypeGuid,
+ &ReturnedObjectIndex))
+ {
+LoopAndUpdateRightsObjects:
+ /* Update the access rights of the target object */
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights |=
+ (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights);
+ DPRINT("Denied rights 0x%08lx of target object at index %lu\n",
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights, ReturnedObjectIndex);
+
+ /* And update the children of the target object */
+ for (ObjectTypeIndex = ReturnedObjectIndex + 1;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ /*
+ * Stop looking for children objects if we hit an object that has
+ * the same level as the target object or less.
+ */
+ Level = ObjectTypeList[ObjectTypeIndex].Level;
+ if (Level <= ObjectTypeList[ReturnedObjectIndex].Level)
+ {
+ DPRINT("We looked for all children objects, stop looking\n");
+ break;
+ }
+
+ /* Update the access right of the child */
+ ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights |=
+ (AccessMask & ~ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights);
+ DPRINT("Denied rights 0x%08lx of child object at index %lu\n",
+ ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights, ObjectTypeIndex);
+ }
+ }
+}
+
+/**
+ * @brief
+ * Allows access of a target object and the children objects
+ * in an object type list.
+ *
+ * @param[in,out] ObjectTypeList
+ * A pointer to an object type list where access is to be
+ * allowed for the target object and its children in the
+ * hierarchy list.
+ *
+ * @param[in] ObjectTypeListLength
+ * The length of the object type list. This length represents
+ * the number of object elements in the list.
+ *
+ * @param[in] AccessMask
+ * The access mask right that is to be allowed for the object.
+ *
+ * @param[in] ObjectTypeGuid
+ * A pointer to a object type GUID, that identifies the object.
+ * This GUID is used to search for the target object in the list.
+ * If this parameter is set to NULL, the function will allow access
+ * starting from the object itself in the list (aka the root).
+ */
+static
+VOID
+SepAllowAccessObjectTypeResultList(
+ _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ ACCESS_MASK AccessMask,
+ _In_opt_ PGUID ObjectTypeGuid)
+{
+ ULONG ObjectTypeIndex;
+ ULONG ReturnedObjectIndex;
+ USHORT Level;
+
+ PAGED_CODE();
+
+ DPRINT("Access rights 0x%08lx\n", AccessMask);
+
+ /*
+ * Begin updating the access rights from the root object
+ * (see comment in SepDenyAccessObjectTypeListMaximum).
+ */
+ if (!ObjectTypeGuid)
+ {
+ DPRINT("No object type provided, updating access rights from root\n");
+ ReturnedObjectIndex = 0;
+ goto LoopAndUpdateRightsObjects;
+ }
+
+ /* Check if that object exists in the list */
+ if (SepObjectTypeGuidInList(ObjectTypeList,
+ ObjectTypeListLength,
+ ObjectTypeGuid,
+ &ReturnedObjectIndex))
+ {
+LoopAndUpdateRightsObjects:
+ /* Update the access rights of the target object */
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights |=
+ (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights);
+ DPRINT("Granted rights 0x%08lx of target object at index %lu\n",
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights, ReturnedObjectIndex);
+
+ /* And update the children of the target object */
+ for (ObjectTypeIndex = ReturnedObjectIndex + 1;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ /*
+ * Stop looking for children objects if we hit an object that has
+ * the same level as the target object or less.
+ */
+ Level = ObjectTypeList[ObjectTypeIndex].Level;
+ if (Level <= ObjectTypeList[ReturnedObjectIndex].Level)
+ {
+ break;
+ }
+
+ /* Update the access right of the child */
+ ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights |=
+ (AccessMask & ~ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights);
+ DPRINT("Granted rights 0x%08lx of child object at index %lu\n",
+ ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights, ObjectTypeIndex);
+ }
+ }
+}
+
+/**
+ * @brief
+ * Denies access of a target object in the object type
+ * list. This access is denied for the whole hierarchy
+ * in the list.
+ *
+ * @param[in,out] ObjectTypeList
+ * A pointer to an object type list where access is to be
+ * denied for the target object. This operation applies
+ * for the entire hierarchy of the object type list.
+ *
+ * @param[in] ObjectTypeListLength
+ * The length of the object type list. This length represents
+ * the number of object elements in the list.
+ *
+ * @param[in] AccessMask
+ * The access mask right that is to be denied for the object.
+ *
+ * @param[in] ObjectTypeGuid
+ * A pointer to a object type GUID, that identifies the object.
+ * This GUID is used to search for the target object in the list.
+ * If this parameter is set to NULL, the function will deny access
+ * to the object itself in the list (aka the root).
+ *
+ * @param[out] BreakOnDeny
+ * A pointer returned boolean value to the caller. The function
+ * will return TRUE if the requested remaining right is denied
+ * by the ACE, otherwise it returns FALSE.
+ */
+static
+VOID
+SepDenyAccessObjectTypeList(
+ _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ ACCESS_MASK AccessMask,
+ _In_opt_ PGUID ObjectTypeGuid,
+ _Out_opt_ PBOOLEAN BreakOnDeny)
+{
+ ULONG ReturnedObjectIndex;
+ BOOLEAN MustBreak;
+
+ PAGED_CODE();
+
+ DPRINT("Access rights 0x%08lx\n", AccessMask);
+
+ /* Assume we do not want to break at first */
+ MustBreak = FALSE;
+
+ /*
+ * If no object type was supplied then tell the caller it has to break on
+ * searching for other ACEs if the requested remaining access right is
+ * denied by the deny ACE itself. Track down that denied right too.
+ */
+ if (!ObjectTypeGuid)
+ {
+ if (ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights & AccessMask)
+ {
+ DPRINT("Root object requests remaining access right that is denied 0x%08lx\n", AccessMask);
+ MustBreak = TRUE;
+ }
+
+ ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights |=
+ (AccessMask & ~ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights);
+ DPRINT("Denied rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights);
+ goto Quit;
+ }
+
+ /*
+ * If the object exists tell the caller it has to break down if the requested
+ * remaining access right is denied by the ACE. Track down the denied right too.
+ */
+ if (SepObjectTypeGuidInList(ObjectTypeList,
+ ObjectTypeListLength,
+ ObjectTypeGuid,
+ &ReturnedObjectIndex))
+ {
+ if (ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights & AccessMask)
+ {
+ DPRINT("Object at index %lu requests remaining access right that is denied 0x%08lx\n", ReturnedObjectIndex, AccessMask);
+ MustBreak = TRUE;
+ }
+
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights |=
+ (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights);
+ DPRINT("Denied rights 0x%08lx of object at index %lu\n",
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights, ReturnedObjectIndex);
+ }
+
+Quit:
+ /* Signal the caller he has to break if he wants to */
+ if (BreakOnDeny)
+ {
+ *BreakOnDeny = MustBreak;
+ }
+}
+
+/**
+ * @brief
+ * Allows access of a target object in the object type
+ * list. This access is allowed for the whole hierarchy
+ * in the list.
+ *
+ * @param[in,out] ObjectTypeList
+ * A pointer to an object type list where access is to be
+ * allowed for the target object. This operation applies
+ * for the entire hierarchy of the object type list.
+ *
+ * @param[in] ObjectTypeListLength
+ * The length of the object type list. This length represents
+ * the number of object elements in the list.
+ *
+ * @param[in] AccessMask
+ * The access mask right that is to be allowed for the object.
+ *
+ * @param[in] RemoveRemainingRights
+ * If set to TRUE, the function will remove the remaining rights
+ * of a target object. It will also grant access of the said object.
+ * Otherwise if set to FALSE, the function will only grant access.
+ *
+ * @param[in] ObjectTypeGuid
+ * A pointer to a object type GUID, that identifies the object.
+ * This GUID is used to search for the target object in the list.
+ * If this parameter is set to NULL, the function will allow access
+ * to the object itself in the list (aka the root).
+ */
+static
+VOID
+SepAllowAccessObjectTypeList(
+ _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ BOOLEAN RemoveRemainingRights,
+ _In_opt_ PGUID ObjectTypeGuid)
+{
+ ULONG ReturnedObjectIndex;
+
+ PAGED_CODE();
+
+ DPRINT("Access rights 0x%08lx\n", AccessMask);
+
+ /*
+ * If no object type was supplied then remove the remaining rights
+ * of the object itself, the root. Track down that right to the
+ * granted rights as well.
+ */
+ if (!ObjectTypeGuid)
+ {
+ if (RemoveRemainingRights)
+ {
+ ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights &= ~AccessMask;
+ DPRINT("Remaining rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights);
+ }
+
+ ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights |=
+ (AccessMask & ~ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights);
+ DPRINT("Granted rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights);
+ return;
+ }
+
+ /*
+ * Grant access to the object if it exists by removing the remaining
+ * rights. Unlike the NtAccessCheckByTypeResultList variant we do not
+ * care about the children of the target object beccause NtAccessCheckByType
+ * will either grant or deny access to the entire hierarchy of the list.
+ */
+ if (SepObjectTypeGuidInList(ObjectTypeList,
+ ObjectTypeListLength,
+ ObjectTypeGuid,
+ &ReturnedObjectIndex))
+ {
+ /* Remove the remaining rights of that object */
+ if (RemoveRemainingRights)
+ {
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights &= ~AccessMask;
+ DPRINT("Remaining rights of object 0x%08lx at index %lu\n",
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights, ReturnedObjectIndex);
+ }
+
+ /* And track it down to the granted access rights */
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights |=
+ (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights);
+ DPRINT("Granted rights of object 0x%08lx at index %lu\n",
+ ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights, ReturnedObjectIndex);
+ }
+}
+
/**
* @brief
* Analyzes an access control entry that is present in a discretionary
@@ -78,11 +443,19 @@
* question represents the number of elements in such array. This parameter must be 0
* if no array list is provided.
*
+ * @param[in] UseResultList
+ * This parameter is to used to determine how to perform an object type access check.
+ * If set to TRUE, the function will either grant or deny access to the object and sub-objects
+ * in the hierarchy list. If set to FALSE, the function will either grant or deny access to
+ * the target that will affect the entire hierarchy of the list. This parameter is used
+ * if the access action type is AccessCheckMaximum.
+ *
* @param[in,out] AccessCheckRights
* A pointer to a structure that contains the access check rights. This function fills
* up this structure with remaining, granted and denied rights to the caller for
* access check. Henceforth, this parameter must not be NULL!
*/
+static
VOID
SepAnalyzeAcesFromDacl(
_In_ ACCESS_CHECK_RIGHT_TYPE ActionType,
@@ -93,15 +466,19 @@ SepAnalyzeAcesFromDacl(
_In_ BOOLEAN IsTokenRestricted,
_In_opt_ PSID PrincipalSelfSid,
_In_ PGENERIC_MAPPING GenericMapping,
- _In_opt_ POBJECT_TYPE_LIST ObjectTypeList,
+ _In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
_In_ ULONG ObjectTypeListLength,
+ _In_ BOOLEAN UseResultList,
_Inout_ PACCESS_CHECK_RIGHTS AccessCheckRights)
{
NTSTATUS Status;
PACE CurrentAce;
ULONG AceIndex;
+ ULONG ObjectTypeIndex;
PSID Sid;
+ PGUID ObjectTypeGuid;
ACCESS_MASK Access;
+ BOOLEAN BreakOnDeny;
PAGED_CODE();
@@ -109,10 +486,6 @@ SepAnalyzeAcesFromDacl(
ASSERT(Dacl);
ASSERT(AccessToken);
- /* TODO: To be removed once we support object type handling in Se */
- DBG_UNREFERENCED_PARAMETER(ObjectTypeList);
- DBG_UNREFERENCED_PARAMETER(ObjectTypeListLength);
-
/* TODO: To be removed once we support compound ACEs handling in Se */
DBG_UNREFERENCED_PARAMETER(PrimaryAccessToken);
@@ -160,7 +533,7 @@ SepAnalyzeAcesFromDacl(
/* Deny access rights that have not been granted yet */
AccessCheckRights->DeniedAccessRights |= (Access & ~AccessCheckRights->GrantedAccessRights);
- DPRINT("SepAnalyzeAcesFromDacl(): DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights);
+ DPRINT("DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights);
}
}
else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
@@ -182,12 +555,108 @@ SepAnalyzeAcesFromDacl(
/* Grant access rights that have not been denied yet */
AccessCheckRights->GrantedAccessRights |= (Access & ~AccessCheckRights->DeniedAccessRights);
- DPRINT("SepAnalyzeAcesFromDacl(): GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights);
+ DPRINT("GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights);
+ }
+ }
+ else if (CurrentAce->Header.AceType == ACCESS_DENIED_OBJECT_ACE_TYPE)
+ {
+ /* Get the SID and object type from this ACE */
+ Sid = SepGetSidFromAce(ACCESS_DENIED_OBJECT_ACE_TYPE, CurrentAce);
+ ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, TRUE);
+ ASSERT(Sid);
+
+ if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
+ {
+ /* Get this access right from the ACE */
+ Access = CurrentAce->AccessMask;
+
+ /* Map this access right if it has a generic mask right */
+ if ((Access & GENERIC_ACCESS) && GenericMapping)
+ {
+ RtlMapGenericMask(&Access, GenericMapping);
+ }
+
+ /* If no list was passed treat this is as ACCESS_DENIED_ACE_TYPE */
+ if (!ObjectTypeList && !ObjectTypeListLength)
+ {
+ AccessCheckRights->DeniedAccessRights |= (Access & ~AccessCheckRights->GrantedAccessRights);
+ DPRINT("DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights);
+ }
+ else if (!UseResultList)
+ {
+ /*
+ * We have an object type list but the caller wants to deny access
+ * to the entire hierarchy list. Evaluate the rights of the object
+ * for the whole list. Ignore what the function tells us if we have
+ * to break on deny or not because we only want to keep track of
+ * denied rights.
+ */
+ SepDenyAccessObjectTypeList(ObjectTypeList,
+ ObjectTypeListLength,
+ Access,
+ ObjectTypeGuid,
+ NULL);
+ }
+ else
+ {
+ /* Otherwise evaluate the access rights for each sub-object */
+ SepDenyAccessObjectTypeResultList(ObjectTypeList,
+ ObjectTypeListLength,
+ Access,
+ ObjectTypeGuid);
+ }
+ }
+ }
+ else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE)
+ {
+ /* Get the SID and object type from this ACE */
+ Sid = SepGetSidFromAce(ACCESS_ALLOWED_OBJECT_ACE_TYPE, CurrentAce);
+ ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, FALSE);
+ ASSERT(Sid);
+
+ if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
+ {
+ /* Get this access right from the ACE */
+ Access = CurrentAce->AccessMask;
+
+ /* Map this access right if it has a generic mask right */
+ if ((Access & GENERIC_ACCESS) && GenericMapping)
+ {
+ RtlMapGenericMask(&Access, GenericMapping);
+ }
+
+ /* If no list was passed treat this is as ACCESS_ALLOWED_ACE_TYPE */
+ if (!ObjectTypeList && !ObjectTypeListLength)
+ {
+ AccessCheckRights->GrantedAccessRights |= (Access & ~AccessCheckRights->DeniedAccessRights);
+ DPRINT("GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights);
+ }
+ else if (!UseResultList)
+ {
+ /*
+ * We have an object type list but the caller wants to allow access
+ * to the entire hierarchy list. Evaluate the rights of the object
+ * for the whole list.
+ */
+ SepAllowAccessObjectTypeList(ObjectTypeList,
+ ObjectTypeListLength,
+ Access,
+ FALSE,
+ ObjectTypeGuid);
+ }
+ else
+ {
+ /* Otherwise evaluate the access rights for each sub-object */
+ SepAllowAccessObjectTypeResultList(ObjectTypeList,
+ ObjectTypeListLength,
+ Access,
+ ObjectTypeGuid);
+ }
}
}
else
{
- DPRINT1("SepAnalyzeAcesFromDacl(): Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
+ DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
}
}
}
@@ -207,6 +676,17 @@ SepAnalyzeAcesFromDacl(
ASSERT(RemainingAccess != 0);
AccessCheckRights->RemainingAccessRights = RemainingAccess;
+ /* Fill the remaining rights of each object in the list if we have one */
+ if (ObjectTypeList && (ObjectTypeListLength != 0))
+ {
+ for (ObjectTypeIndex = 0;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights = RemainingAccess;
+ }
+ }
+
/* Loop over the DACL to retrieve ACEs */
for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++)
{
@@ -246,7 +726,7 @@ SepAnalyzeAcesFromDacl(
*/
if (AccessCheckRights->RemainingAccessRights & Access)
{
- DPRINT("SepAnalyzeAcesFromDacl(): Refuted access 0x%08lx\n", Access);
+ DPRINT("Refuted access 0x%08lx\n", Access);
AccessCheckRights->DeniedAccessRights |= Access;
break;
}
@@ -270,17 +750,107 @@ SepAnalyzeAcesFromDacl(
}
/* Remove the remaining rights */
- DPRINT("SepAnalyzeAcesFromDacl(): RemainingAccessRights 0x%08lx Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access);
+ DPRINT("RemainingAccessRights 0x%08lx Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access);
AccessCheckRights->RemainingAccessRights &= ~Access;
- DPRINT("SepAnalyzeAcesFromDacl(): RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights);
+ DPRINT("RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights);
/* Track the granted access right */
AccessCheckRights->GrantedAccessRights |= Access;
}
}
+ else if (CurrentAce->Header.AceType == ACCESS_DENIED_OBJECT_ACE_TYPE)
+ {
+ /* Get the SID and object type from this ACE */
+ Sid = SepGetSidFromAce(ACCESS_DENIED_OBJECT_ACE_TYPE, CurrentAce);
+ ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, TRUE);
+ ASSERT(Sid);
+
+ if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
+ {
+ /* Get this access right from the ACE */
+ Access = CurrentAce->AccessMask;
+
+ /* Map this access right if it has a generic mask right */
+ if ((Access & GENERIC_ACCESS) && GenericMapping)
+ {
+ RtlMapGenericMask(&Access, GenericMapping);
+ }
+
+ /* If no list was passed treat this is as ACCESS_DENIED_ACE_TYPE */
+ if (!ObjectTypeList && !ObjectTypeListLength)
+ {
+ if (AccessCheckRights->RemainingAccessRights & Access)
+ {
+ DPRINT("Refuted access 0x%08lx\n", Access);
+ AccessCheckRights->DeniedAccessRights |= Access;
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Otherwise evaluate the rights of the object for the entire list.
+ * The function will signal us if the caller requested a right that is
+ * denied by the ACE of an object in the list.
+ */
+ SepDenyAccessObjectTypeList(ObjectTypeList,
+ ObjectTypeListLength,
+ Access,
+ ObjectTypeGuid,
+ &BreakOnDeny);
+
+ /* We are acknowledged the caller requested a denied right */
+ if (BreakOnDeny)
+ {
+ DPRINT("Refuted access 0x%08lx\n", Access);
+ break;
+ }
+ }
+ }
+ }
+ else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE)
+ {
+ /* Get the SID and object type from this ACE */
+ Sid = SepGetSidFromAce(ACCESS_ALLOWED_OBJECT_ACE_TYPE, CurrentAce);
+ ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, FALSE);
+ ASSERT(Sid);
+
+ if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
+ {
+ /* Get this access right from the ACE */
+ Access = CurrentAce->AccessMask;
+
+ /* Map this access right if it has a generic mask right */
+ if ((Access & GENERIC_ACCESS) && GenericMapping)
+ {
+ RtlMapGenericMask(&Access, GenericMapping);
+ }
+
+ /* If no list was passed treat this is as ACCESS_ALLOWED_ACE_TYPE */
+ if (!ObjectTypeList && !ObjectTypeListLength)
+ {
+ /* Remove the remaining rights */
+ DPRINT("RemainingAccessRights 0x%08lx Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access);
+ AccessCheckRights->RemainingAccessRights &= ~Access;
+ DPRINT("RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights);
+
+ /* Track the granted access right */
+ AccessCheckRights->GrantedAccessRights |= Access;
+ }
+ else
+ {
+ /* Otherwise evaluate the rights of the object for the entire list */
+ SepAllowAccessObjectTypeList(ObjectTypeList,
+ ObjectTypeListLength,
+ Access,
+ TRUE,
+ ObjectTypeGuid);
+ }
+ }
+ }
else
{
- DPRINT1("SepAnalyzeAcesFromDacl(): Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
+ DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
}
}
}
@@ -296,11 +866,10 @@ SepAnalyzeAcesFromDacl(
/**
* @brief
- * Private function that determines whether security access rights can be given
- * to the calling thread in order to access an object depending on the security
- * descriptor and other security context entities, such as an owner. This
- * function is the heart and brain of the whole access check algorithm in
- * the kernel.
+ * Private worker function that determines whether security access rights can be
+ * givento the calling thread in order to access an object depending on the
+ * security descriptor and other security context entities, such as an owner. This
+ * function is the heart and brain of the whole access check algorithm in the kernel.
*
* @param[in] ClientAccessToken
* A pointer to a client (thread) access token that requests access rights
@@ -368,15 +937,15 @@ SepAnalyzeAcesFromDacl(
* Returns TRUE if access onto the specific object is allowed, FALSE
* otherwise.
*/
+static
BOOLEAN
-NTAPI
-SepAccessCheck(
+SepAccessCheckWorker(
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
_In_opt_ PACCESS_TOKEN ClientAccessToken,
_In_ PACCESS_TOKEN PrimaryAccessToken,
_In_opt_ PSID PrincipalSelfSid,
_In_ ACCESS_MASK DesiredAccess,
- _In_opt_ POBJECT_TYPE_LIST ObjectTypeList,
+ _In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
_In_ ULONG ObjectTypeListLength,
_In_ ACCESS_MASK PreviouslyGrantedAccess,
_In_ PGENERIC_MAPPING GenericMapping,
@@ -387,12 +956,16 @@ SepAccessCheck(
_Out_ PNTSTATUS AccessStatusList)
{
ACCESS_MASK RemainingAccess;
- ULONG ResultListLength;
+ ACCESS_MASK WantedRights;
+ ACCESS_MASK MaskDesired;
+ ACCESS_MASK GrantedRights = 0;
ULONG ResultListIndex;
+ ULONG ObjectTypeIndex;
PACL Dacl;
BOOLEAN Present;
BOOLEAN Defaulted;
NTSTATUS Status;
+ BOOLEAN AccessIsGranted = FALSE;
PACCESS_TOKEN Token = NULL;
ACCESS_CHECK_RIGHTS AccessCheckRights = {0};
@@ -408,7 +981,7 @@ SepAccessCheck(
if (!PreviouslyGrantedAccess)
{
/* Then there's nothing to give */
- DPRINT1("SepAccessCheck(): The caller has no previously granted access gained!\n");
+ DPRINT1("The caller has no previously granted access gained!\n");
Status = STATUS_ACCESS_DENIED;
goto ReturnCommonStatus;
}
@@ -427,6 +1000,23 @@ SepAccessCheck(
/* Initialize remaining access rights */
RemainingAccess = DesiredAccess;
+ /*
+ * Initialize the required rights if the caller wants to know access
+ * for the object and each sub-object in the list.
+ */
+ if (UseResultList)
+ {
+ if (DesiredAccess & MAXIMUM_ALLOWED)
+ {
+ WantedRights = (DesiredAccess | PreviouslyGrantedAccess) & ~MAXIMUM_ALLOWED;
+ MaskDesired = ~MAXIMUM_ALLOWED;
+ }
+ else
+ {
+ WantedRights = MaskDesired = DesiredAccess | PreviouslyGrantedAccess;
+ }
+ }
+
/*
* Obtain the token provided by the caller. Client (or also
* called impersonation or thread) token takes precedence over
@@ -501,15 +1091,19 @@ SepAccessCheck(
}
else
{
- DPRINT1("SepAccessCheck(): The DACL has no ACEs and the caller has no previously granted access!\n");
+ DPRINT1("The DACL has no ACEs and the caller has no previously granted access!\n");
PreviouslyGrantedAccess = 0;
Status = STATUS_ACCESS_DENIED;
}
goto ReturnCommonStatus;
}
- /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */
- if (DesiredAccess & MAXIMUM_ALLOWED)
+ /*
+ * Determine the MAXIMUM_ALLOWED access rights according to the DACL.
+ * Or if the caller is supplying a list of object types then determine
+ * the rights of each object on that list.
+ */
+ if ((DesiredAccess & MAXIMUM_ALLOWED) || UseResultList)
{
/* Perform access checks against ACEs from this DACL */
SepAnalyzeAcesFromDacl(AccessCheckMaximum,
@@ -522,6 +1116,7 @@ SepAccessCheck(
GenericMapping,
ObjectTypeList,
ObjectTypeListLength,
+ UseResultList,
&AccessCheckRights);
/*
@@ -540,33 +1135,145 @@ SepAccessCheck(
GenericMapping,
ObjectTypeList,
ObjectTypeListLength,
+ UseResultList,
&AccessCheckRights);
}
- /* Fail if some rights have not been granted */
- RemainingAccess &= ~(MAXIMUM_ALLOWED | AccessCheckRights.GrantedAccessRights);
- if (RemainingAccess != 0)
+ /* The caller did not provide an object type list, check access only for that object */
+ if (!ObjectTypeList && !ObjectTypeListLength)
{
- DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess);
- PreviouslyGrantedAccess = 0;
- Status = STATUS_ACCESS_DENIED;
- goto ReturnCommonStatus;
- }
+ /* Fail if some rights have not been granted */
+ RemainingAccess &= ~(MAXIMUM_ALLOWED | AccessCheckRights.GrantedAccessRights);
+ if (RemainingAccess != 0)
+ {
+ DPRINT1("Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess);
+ PreviouslyGrantedAccess = 0;
+ Status = STATUS_ACCESS_DENIED;
+ goto ReturnCommonStatus;
+ }
- /* Set granted access right and access status */
- PreviouslyGrantedAccess |= AccessCheckRights.GrantedAccessRights;
- if (PreviouslyGrantedAccess != 0)
- {
- Status = STATUS_SUCCESS;
+ /* Set granted access right and access status */
+ PreviouslyGrantedAccess |= AccessCheckRights.GrantedAccessRights;
+ if (PreviouslyGrantedAccess != 0)
+ {
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ DPRINT1("Failed to grant access rights. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess);
+ Status = STATUS_ACCESS_DENIED;
+ }
+
+ /* We are done here */
+ goto ReturnCommonStatus;
}
- else
+ else if (!UseResultList)
{
- DPRINT1("SepAccessCheck(): Failed to grant access rights. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess);
- Status = STATUS_ACCESS_DENIED;
- }
+ /*
+ * We have a list but the caller wants to know if access can be granted
+ * to an object in the list. Access will either be granted or denied
+ * to the whole hierarchy of the list. Look for every object in the list
+ * that has granted access rights and collect them.
+ */
+ for (ObjectTypeIndex = 0;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights != 0)
+ {
+ GrantedRights |= ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights;
+ }
+ }
- /* We have successfully granted all the rights */
- goto ReturnCommonStatus;
+ /* Now check if acccess can be granted */
+ RemainingAccess &= ~(MAXIMUM_ALLOWED | GrantedRights);
+ if (RemainingAccess != 0)
+ {
+ DPRINT1("Failed to grant access rights to the whole object hierarchy list. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n",
+ RemainingAccess, DesiredAccess);
+ PreviouslyGrantedAccess = 0;
+ Status = STATUS_ACCESS_DENIED;
+ goto ReturnCommonStatus;
+ }
+
+ /* Set granted access right and access status */
+ PreviouslyGrantedAccess |= GrantedRights;
+ if (PreviouslyGrantedAccess != 0)
+ {
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ DPRINT1("Failed to grant access rights to the whole object hierarchy list. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n",
+ DesiredAccess);
+ Status = STATUS_ACCESS_DENIED;
+ }
+
+ /* We are done here */
+ goto ReturnCommonStatus;
+ }
+ else
+ {
+ /*
+ * We have a list and the caller wants to know access for each
+ * sub-object in the list. Report the access status and granted
+ * rights for the object and each sub-object in the list.
+ */
+ for (ObjectTypeIndex = 0;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ /* Check if we have some rights */
+ GrantedRights = (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights | PreviouslyGrantedAccess) & MaskDesired;
+ if (GrantedRights != 0)
+ {
+ /*
+ * If we still have some remaining rights to grant the ultimate
+ * conclusion is that the caller has no access to the object itself.
+ */
+ RemainingAccess = (~GrantedRights & WantedRights);
+ if (RemainingAccess != 0)
+ {
+ DPRINT1("Failed to grant access rights at specific object at index %lu. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n",
+ ObjectTypeIndex, RemainingAccess, DesiredAccess);
+ AccessStatusList[ObjectTypeIndex] = STATUS_ACCESS_DENIED;
+ }
+ else
+ {
+ AccessStatusList[ObjectTypeIndex] = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ /* No access is given */
+ DPRINT1("Failed to grant access rights at specific object at index %lu. No access is given\n", ObjectTypeIndex);
+ AccessStatusList[ObjectTypeIndex] = STATUS_ACCESS_DENIED;
+ }
+
+ /* Return the access rights to the caller */
+ GrantedAccessList[ObjectTypeIndex] = GrantedRights;
+ }
+
+ /*
+ * We have built a list of access statuses for each object but
+ * we still need to figure out the common status for the
+ * function. The same status code will be used to check if
+ * we should report any security debug stuff once we are done.
+ */
+ Status = STATUS_SUCCESS;
+ for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
+ {
+ /* There is at least one sub-object of which access cannot be granted */
+ if (AccessStatusList[ResultListIndex] == STATUS_ACCESS_DENIED)
+ {
+ Status = AccessStatusList[ResultListIndex];
+ break;
+ }
+ }
+
+ /* We are done here */
+ goto ReturnCommonStatus;
+ }
}
/* Grant rights according to the DACL */
@@ -580,15 +1287,45 @@ SepAccessCheck(
GenericMapping,
ObjectTypeList,
ObjectTypeListLength,
+ UseResultList,
&AccessCheckRights);
- /* Fail if some rights have not been granted */
- if (AccessCheckRights.RemainingAccessRights != 0)
+ /* The caller did not provide an object type list, check access only for that object */
+ if (!ObjectTypeList && !ObjectTypeListLength)
{
- DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess);
- PreviouslyGrantedAccess = 0;
- Status = STATUS_ACCESS_DENIED;
- goto ReturnCommonStatus;
+ /* Fail if some rights have not been granted */
+ if (AccessCheckRights.RemainingAccessRights != 0)
+ {
+ DPRINT1("Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess);
+ PreviouslyGrantedAccess = 0;
+ Status = STATUS_ACCESS_DENIED;
+ goto ReturnCommonStatus;
+ }
+ }
+ else
+ {
+ /*
+ * We have an object type list, look for the object of which
+ * remaining rights are all granted.
+ */
+ for (ObjectTypeIndex = 0;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights == 0)
+ {
+ AccessIsGranted = TRUE;
+ break;
+ }
+ }
+
+ if (!AccessIsGranted)
+ {
+ DPRINT1("Failed to grant access rights to the whole object hierarchy list. DesiredAccess = 0x%08lx\n", DesiredAccess);
+ PreviouslyGrantedAccess = 0;
+ Status = STATUS_ACCESS_DENIED;
+ goto ReturnCommonStatus;
+ }
}
/*
@@ -607,15 +1344,49 @@ SepAccessCheck(
GenericMapping,
ObjectTypeList,
ObjectTypeListLength,
+ UseResultList,
&AccessCheckRights);
- /* Fail if some rights have not been granted */
- if (AccessCheckRights.RemainingAccessRights != 0)
+ /* The caller did not provide an object type list, check access only for that object */
+ if (!ObjectTypeList && !ObjectTypeListLength)
{
- DPRINT1("SepAccessCheck(): Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess);
- PreviouslyGrantedAccess = 0;
- Status = STATUS_ACCESS_DENIED;
- goto ReturnCommonStatus;
+ /* Fail if some rights have not been granted */
+ if (AccessCheckRights.RemainingAccessRights != 0)
+ {
+ DPRINT1("Failed to grant access rights. RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess);
+ PreviouslyGrantedAccess = 0;
+ Status = STATUS_ACCESS_DENIED;
+ goto ReturnCommonStatus;
+ }
+ }
+ else
+ {
+ /*
+ * We have an object type list, look for the object of which remaining
+ * rights are all granted. The user may have access to the requested
+ * object but on a restricted token case the user is only granted partial
+ * access. If access is denied to restricted SIDs, the bottom line is that
+ * access is denied to the user.
+ */
+ AccessIsGranted = FALSE;
+ for (ObjectTypeIndex = 0;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights == 0)
+ {
+ AccessIsGranted = TRUE;
+ break;
+ }
+ }
+
+ if (!AccessIsGranted)
+ {
+ DPRINT1("Failed to grant access rights to the whole object hierarchy list. DesiredAccess = 0x%08lx\n", DesiredAccess);
+ PreviouslyGrantedAccess = 0;
+ Status = STATUS_ACCESS_DENIED;
+ goto ReturnCommonStatus;
+ }
}
}
@@ -625,7 +1396,7 @@ SepAccessCheck(
/* Fail if no rights have been granted */
if (PreviouslyGrantedAccess == 0)
{
- DPRINT1("SepAccessCheck(): Failed to grant access rights. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess);
+ DPRINT1("Failed to grant access rights. PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess);
Status = STATUS_ACCESS_DENIED;
goto ReturnCommonStatus;
}
@@ -637,11 +1408,10 @@ SepAccessCheck(
Status = STATUS_SUCCESS;
ReturnCommonStatus:
- ResultListLength = UseResultList ? ObjectTypeListLength : 1;
- for (ResultListIndex = 0; ResultListIndex < ResultListLength; ResultListIndex++)
+ if (!UseResultList)
{
- GrantedAccessList[ResultListIndex] = PreviouslyGrantedAccess;
- AccessStatusList[ResultListIndex] = Status;
+ *GrantedAccessList = PreviouslyGrantedAccess;
+ *AccessStatusList = Status;
}
#if DBG
@@ -650,67 +1420,25 @@ ReturnCommonStatus:
{
SepDumpSdDebugInfo(SecurityDescriptor);
SepDumpTokenDebugInfo(Token);
- SepDumpAccessRightsStats(&AccessCheckRights);
+
+ if (ObjectTypeList && (ObjectTypeListLength != 0))
+ {
+ SepDumpAccessAndStatusList(GrantedAccessList,
+ AccessStatusList,
+ UseResultList,
+ ObjectTypeList,
+ ObjectTypeListLength);
+ }
+ else
+ {
+ SepDumpAccessRightsStats(&AccessCheckRights);
+ }
}
#endif
return NT_SUCCESS(Status);
}
-/**
- * @brief
- * Retrieves the main user from a security descriptor.
- *
- * @param[in] SecurityDescriptor
- * A valid allocated security descriptor structure where the owner
- * is to be retrieved.
- *
- * @return
- * Returns a SID that represents the main user (owner).
- */
-static PSID
-SepGetSDOwner(
- _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor)
-{
- PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
- PSID Owner;
-
- if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
- Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
- (ULONG_PTR)SecurityDescriptor);
- else
- Owner = (PSID)SecurityDescriptor->Owner;
-
- return Owner;
-}
-
-/**
- * @brief
- * Retrieves the group from a security descriptor.
- *
- * @param[in] SecurityDescriptor
- * A valid allocated security descriptor structure where the group
- * is to be retrieved.
- *
- * @return
- * Returns a SID that represents a group.
- */
-static PSID
-SepGetSDGroup(
- _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor)
-{
- PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
- PSID Group;
-
- if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
- Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
- (ULONG_PTR)SecurityDescriptor);
- else
- Group = (PSID)SecurityDescriptor->Group;
-
- return Group;
-}
-
/**
* @brief
* Retrieves the length size of a set list of privileges structure.
@@ -736,71 +1464,133 @@ SepGetPrivilegeSetLength(
(PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES));
}
-/* PUBLIC FUNCTIONS ***********************************************************/
-
/**
* @brief
- * Determines whether security access rights can be given to an object
- * depending on the security descriptor and other security context
- * entities, such as an owner.
+ * Internal function that performs a security check against the
+ * client who requests access on a resource object. This function
+ * is used by access check NT system calls.
*
* @param[in] SecurityDescriptor
- * Security descriptor of the object that is being accessed.
+ * A pointer to a security descriptor that identifies the security
+ * information of an object being accessed. This function walks
+ * through this descriptor for any ACLs and respective access
+ * rights if access can be granted.
*
- * @param[in] SubjectSecurityContext
- * The captured subject security context.
+ * @param[in] ClientToken
+ * A handle to an access token, that identifies the client of which
+ * requests access to the target object.
*
- * @param[in] SubjectContextLocked
- * If set to TRUE, the caller acknowledges that the subject context
- * has already been locked by the caller himself. If set to FALSE,
- * the function locks the subject context.
+ * @param[in] PrincipalSelfSid
+ * A pointer to a principal self SID. This parameter can be NULL if
+ * the associated object being checked for access does not represent
+ * a principal.
*
* @param[in] DesiredAccess
- * Access right bitmask that the calling thread wants to acquire.
- *
- * @param[in] PreviouslyGrantedAccess
- * The access rights previously acquired in the past.
- *
- * @param[out] Privileges
- * The returned set of privileges.
+ * The access right bitmask where the client wants to acquire. This
+ * can be an OR'ed set of multiple access rights or MAXIMUM_ALLOWED
+ * to request all of possible access rights the target object allows.
+ * If only some rights were granted but not all the access is deemed
+ * as denied.
*
* @param[in] GenericMapping
* The generic mapping of access rights of an object type.
*
- * @param[in] AccessMode
- * The processor request level mode.
+ * @param[out] PrivilegeSet
+ * A pointer to a set of privileges that were used to perform the
+ * access check, returned to caller. This function will return no
+ * privileges (privilege count set to 0) if no privileges were used
+ * to accomplish the access check. This parameter must not be NULL!
+ *
+ * @param[in,out] PrivilegeSetLength
+ * The total length size of a set of privileges. This length represents
+ * the count of elements in the privilege set array.
+ *
+ * @param[in] ObjectTypeList
+ * A pointer to a given object type list. If this parameter is not NULL
+ * the function will perform an access check against the main object
+ * and sub-objects of this list. If this parameter is NULL and
+ * ObjectTypeListLength is 0, the function will perform a normal
+ * access check instead.
+ *
+ * @param[in] ObjectTypeListLength
+ * The length of the object type list array, pointed by ObjectTypeList.
+ * This length in question represents the number of elements in such array.
+ * This parameter must be 0 if no array list is provided.
+ *
+ * @param[in] UseResultList
+ * If this parameter is set to TRUE, the function will return the GrantedAccess
+ * and AccessStatus parameter as arrays of granted rights and status value for
+ * each individual object element pointed by ObjectTypeList.
*
* @param[out] GrantedAccess
- * A list of granted access rights.
+ * A pointer to granted access rights, returned to the caller. If ObjectTypeList
+ * is not NULL this paramater is an array of granted access rights for the object
+ * and each individual sub-object of the list.
*
* @param[out] AccessStatus
- * The returned status code specifying why access cannot be made
- * onto an object (if said access is denied in the first place).
+ * A pointer to a status code, returned to the caller. This status code
+ * represents whether access is granted or denied to the client on the
+ * target object. The difference between the status code of the function
+ * is that code indicates whether the function has successfully completed
+ * the access check operation. If ObjectTypeList is not NULL, this
+ * parameter is an array of access status for the object and each individual
+ * sub-object of the list.
*
* @return
- * Returns TRUE if access onto the specific object is allowed, FALSE
- * otherwise.
+ * Returns STATUS_SUCCESS if access check has been done without problems
+ * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned
+ * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned
+ * if the token from the handle is not an impersonation token.
+ * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated
+ * because the current security impersonation level doesn't permit so.
+ * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given
+ * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if
+ * the buffer to the captured privileges has a length that is less than the required
+ * size of the set of privileges. STATUS_INVALID_PARAMETER is returned if the caller
+ * did not provide an object type list but the caller wanted to invoke an object type
+ * result list access check, or if the list is out of order or the list is invalid.
+ * A failure NTSTATUS code is returned otherwise.
+ *
+ * @remarks
+ * The function performs an access check against the object type list,
+ * if provided, depending on the UseResultList parameter. That is, if that
+ * parameter was set to TRUE the function will either grant or deny access
+ * to each individual sub-object and return an array of access status and
+ * granted rights for the corresponding object type list. Otherwise the function
+ * will grant or deny access to the object type list hierarchy as a whole.
*/
-BOOLEAN
-NTAPI
-SeAccessCheck(
+static
+NTSTATUS
+SepAccessCheck(
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
- _In_ BOOLEAN SubjectContextLocked,
+ _In_ HANDLE ClientToken,
+ _In_opt_ PSID PrincipalSelfSid,
_In_ ACCESS_MASK DesiredAccess,
- _In_ ACCESS_MASK PreviouslyGrantedAccess,
- _Out_ PPRIVILEGE_SET* Privileges,
_In_ PGENERIC_MAPPING GenericMapping,
- _In_ KPROCESSOR_MODE AccessMode,
+ _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
+ _Inout_ PULONG PrivilegeSetLength,
+ _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ BOOLEAN UseResultList,
_Out_ PACCESS_MASK GrantedAccess,
_Out_ PNTSTATUS AccessStatus)
{
- BOOLEAN ret;
+ PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
+ POBJECT_TYPE_LIST_INTERNAL CapturedObjectTypeList = NULL;
+ PSID CapturedPrincipalSelfSid = NULL;
+ SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ ACCESS_MASK PreviouslyGrantedAccess = 0;
+ PPRIVILEGE_SET Privileges = NULL;
+ ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength;
+ ULONG ResultListIndex;
+ PTOKEN Token;
+ NTSTATUS Status;
PAGED_CODE();
/* Check if this is kernel mode */
- if (AccessMode == KernelMode)
+ if (PreviousMode == KernelMode)
{
/* Check if kernel wants everything */
if (DesiredAccess & MAXIMUM_ALLOWED)
@@ -808,291 +1598,52 @@ SeAccessCheck(
/* Give it */
*GrantedAccess = GenericMapping->GenericAll;
*GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
- *GrantedAccess |= PreviouslyGrantedAccess;
}
else
{
- /* Give the desired and previous access */
- *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
+ /* Just give the desired access */
+ *GrantedAccess = DesiredAccess;
}
/* Success */
*AccessStatus = STATUS_SUCCESS;
- return TRUE;
- }
-
- /* Check if we didn't get an SD */
- if (!SecurityDescriptor)
- {
- /* Automatic failure */
- *AccessStatus = STATUS_ACCESS_DENIED;
- return FALSE;
- }
-
- /* Check for invalid impersonation */
- if ((SubjectSecurityContext->ClientToken) &&
- (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
- {
- *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
- return FALSE;
+ return STATUS_SUCCESS;
}
- /* Acquire the lock if needed */
- if (!SubjectContextLocked)
- SeLockSubjectContext(SubjectSecurityContext);
-
- /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
- if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
+ /* Protect probe in SEH */
+ _SEH2_TRY
{
- PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
- SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
+ /* Probe all pointers */
+ ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG));
+ ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG));
+ ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG));
- if (SepTokenIsOwner(Token,
- SecurityDescriptor,
- FALSE))
+ /*
+ * Probe the access and status list based on the way
+ * we are going to fill data in.
+ */
+ if (UseResultList)
{
- if (DesiredAccess & MAXIMUM_ALLOWED)
- PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
- else
- PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
-
- DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
- }
- }
+ /* Bail out on an empty list */
+ if (!ObjectTypeListLength)
+ {
+ DPRINT1("The object type list is empty\n");
+ _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
+ }
- if (DesiredAccess == 0)
- {
- *GrantedAccess = PreviouslyGrantedAccess;
- if (PreviouslyGrantedAccess == 0)
- {
- DPRINT1("Request for zero access to an object. Denying.\n");
- *AccessStatus = STATUS_ACCESS_DENIED;
- ret = FALSE;
+ ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK) * ObjectTypeListLength, sizeof(ULONG));
+ ProbeForWrite(AccessStatus, sizeof(NTSTATUS) * ObjectTypeListLength, sizeof(ULONG));
}
else
{
- *AccessStatus = STATUS_SUCCESS;
- ret = TRUE;
+ ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
+ ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
}
+
+ /* Capture the privilege set length and the mapping */
+ CapturedPrivilegeSetLength = *PrivilegeSetLength;
}
- else
- {
- /* Call the internal function */
- ret = SepAccessCheck(SecurityDescriptor,
- SubjectSecurityContext->ClientToken,
- SubjectSecurityContext->PrimaryToken,
- NULL,
- DesiredAccess,
- NULL,
- 0,
- PreviouslyGrantedAccess,
- GenericMapping,
- AccessMode,
- FALSE,
- Privileges,
- GrantedAccess,
- AccessStatus);
- }
-
- /* Release the lock if needed */
- if (!SubjectContextLocked)
- SeUnlockSubjectContext(SubjectSecurityContext);
-
- return ret;
-}
-
-/**
- * @brief
- * Determines whether security access rights can be given to an object
- * depending on the security descriptor. Unlike the regular access check
- * procedure in the NT kernel, the fast traverse check is a faster way
- * to quickly check if access can be made into an object.
- *
- * @param[in] SecurityDescriptor
- * Security descriptor of the object that is being accessed.
- *
- * @param[in] AccessState
- * An access state to determine if the access token in the current
- * security context of the object is an restricted token.
- *
- * @param[in] DesiredAccess
- * The access right bitmask where the calling thread wants to acquire.
- *
- * @param[in] AccessMode
- * Process level request mode.
- *
- * @return
- * Returns TRUE if access onto the specific object is allowed, FALSE
- * otherwise.
- */
-BOOLEAN
-NTAPI
-SeFastTraverseCheck(
- _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _In_ PACCESS_STATE AccessState,
- _In_ ACCESS_MASK DesiredAccess,
- _In_ KPROCESSOR_MODE AccessMode)
-{
- PACL Dacl;
- ULONG AceIndex;
- PKNOWN_ACE Ace;
-
- PAGED_CODE();
-
- ASSERT(AccessMode != KernelMode);
-
- if (SecurityDescriptor == NULL)
- return FALSE;
-
- /* Get DACL */
- Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
- /* If no DACL, grant access */
- if (Dacl == NULL)
- return TRUE;
-
- /* No ACE -> Deny */
- if (!Dacl->AceCount)
- return FALSE;
-
- /* Can't perform the check on restricted token */
- if (AccessState->Flags & TOKEN_IS_RESTRICTED)
- return FALSE;
-
- /* Browse the ACEs */
- for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL));
- AceIndex < Dacl->AceCount;
- AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize))
- {
- if (Ace->Header.AceFlags & INHERIT_ONLY_ACE)
- continue;
-
- /* If access-allowed ACE */
- if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
- {
- /* Check if all accesses are granted */
- if (!(Ace->Mask & DesiredAccess))
- continue;
-
- /* Check SID and grant access if matching */
- if (RtlEqualSid(SeWorldSid, &(Ace->SidStart)))
- return TRUE;
- }
- /* If access-denied ACE */
- else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE)
- {
- /* Here, only check if it denies any access wanted and deny if so */
- if (Ace->Mask & DesiredAccess)
- return FALSE;
- }
- }
-
- /* Faulty, deny */
- return FALSE;
-}
-
-/* SYSTEM CALLS ***************************************************************/
-
-/**
- * @brief
- * Determines whether security access rights can be given to an object
- * depending on the security descriptor and a valid handle to an access
- * token.
- *
- * @param[in] SecurityDescriptor
- * Security descriptor of the object that is being accessed.
- *
- * @param[in] TokenHandle
- * A handle to a token.
- *
- * @param[in] DesiredAccess
- * The access right bitmask where the calling thread wants to acquire.
- *
- * @param[in] GenericMapping
- * The generic mapping of access rights of an object type.
- *
- * @param[out] PrivilegeSet
- * The returned set of privileges.
- *
- * @param[in,out] PrivilegeSetLength
- * The total length size of a set of privileges.
- *
- * @param[out] GrantedAccess
- * A list of granted access rights.
- *
- * @param[out] AccessStatus
- * The returned status code specifying why access cannot be made
- * onto an object (if said access is denied in the first place).
- *
- * @return
- * Returns STATUS_SUCCESS if access check has been done without problems
- * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned
- * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned
- * if the token from the handle is not an impersonation token.
- * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated
- * because the current security impersonation level doesn't permit so.
- * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given
- * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if
- * the buffer to the captured privileges has a length that is less than the required
- * size of the set of privileges. A failure NTSTATUS code is returned otherwise.
- */
-NTSTATUS
-NTAPI
-NtAccessCheck(
- _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _In_ HANDLE TokenHandle,
- _In_ ACCESS_MASK DesiredAccess,
- _In_ PGENERIC_MAPPING GenericMapping,
- _Out_opt_ PPRIVILEGE_SET PrivilegeSet,
- _Inout_ PULONG PrivilegeSetLength,
- _Out_ PACCESS_MASK GrantedAccess,
- _Out_ PNTSTATUS AccessStatus)
-{
- PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
- SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
- KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
- ACCESS_MASK PreviouslyGrantedAccess = 0;
- PPRIVILEGE_SET Privileges = NULL;
- ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength;
- PTOKEN Token;
- NTSTATUS Status;
-
- PAGED_CODE();
-
- /* Check if this is kernel mode */
- if (PreviousMode == KernelMode)
- {
- /* Check if kernel wants everything */
- if (DesiredAccess & MAXIMUM_ALLOWED)
- {
- /* Give it */
- *GrantedAccess = GenericMapping->GenericAll;
- *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
- }
- else
- {
- /* Just give the desired access */
- *GrantedAccess = DesiredAccess;
- }
-
- /* Success */
- *AccessStatus = STATUS_SUCCESS;
- return STATUS_SUCCESS;
- }
-
- /* Protect probe in SEH */
- _SEH2_TRY
- {
- /* Probe all pointers */
- ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG));
- ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG));
- ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG));
- ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
- ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
-
- /* Capture the privilege set length and the mapping */
- CapturedPrivilegeSetLength = *PrivilegeSetLength;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
@@ -1101,10 +1652,13 @@ NtAccessCheck(
/* Check for unmapped access rights */
if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
+ {
+ DPRINT1("Some generic rights are not mapped\n");
return STATUS_GENERIC_NOT_MAPPED;
+ }
/* Reference the token */
- Status = ObReferenceObjectByHandle(TokenHandle,
+ Status = ObReferenceObjectByHandle(ClientToken,
TOKEN_QUERY,
SeTokenObjectType,
PreviousMode,
@@ -1112,7 +1666,7 @@ NtAccessCheck(
NULL);
if (!NT_SUCCESS(Status))
{
- DPRINT("Failed to reference token (Status %lx)\n", Status);
+ DPRINT1("Failed to reference token (Status 0x%08lx)\n", Status);
return Status;
}
@@ -1127,11 +1681,23 @@ NtAccessCheck(
/* Check the impersonation level */
if (Token->ImpersonationLevel < SecurityIdentification)
{
- DPRINT("Impersonation level < SecurityIdentification\n");
+ DPRINT1("Impersonation level < SecurityIdentification\n");
ObDereferenceObject(Token);
return STATUS_BAD_IMPERSONATION_LEVEL;
}
+ /* Capture the object type list, the list is probed by the function itself */
+ Status = SeCaptureObjectTypeList(ObjectTypeList,
+ ObjectTypeListLength,
+ PreviousMode,
+ &CapturedObjectTypeList);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture the object type list (Status 0x%08lx)\n", Status);
+ ObDereferenceObject(Token);
+ return Status;
+ }
+
/* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
Status = SePrivilegePolicyCheck(&DesiredAccess,
&PreviouslyGrantedAccess,
@@ -1141,10 +1707,29 @@ NtAccessCheck(
PreviousMode);
if (!NT_SUCCESS(Status))
{
- DPRINT("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status);
+ DPRINT1("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status);
+ SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
ObDereferenceObject(Token);
- *AccessStatus = Status;
- *GrantedAccess = 0;
+
+ /*
+ * The caller does not have the required access to do an access check.
+ * Propagate the access and status for the whole hierarchy of the list
+ * or just to single target object.
+ */
+ if (UseResultList)
+ {
+ for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
+ {
+ AccessStatus[ResultListIndex] = Status;
+ GrantedAccess[ResultListIndex] = 0;
+ }
+ }
+ else
+ {
+ *AccessStatus = Status;
+ *GrantedAccess = 0;
+ }
+
return STATUS_SUCCESS;
}
@@ -1159,8 +1744,9 @@ NtAccessCheck(
/* Fail if the privilege set buffer is too small */
if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength)
{
- ObDereferenceObject(Token);
SeFreePrivileges(Privileges);
+ SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
+ ObDereferenceObject(Token);
*PrivilegeSetLength = RequiredPrivilegeSetLength;
return STATUS_BUFFER_TOO_SMALL;
}
@@ -1180,6 +1766,7 @@ NtAccessCheck(
/* Fail if the privilege set buffer is too small */
if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET))
{
+ SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
ObDereferenceObject(Token);
*PrivilegeSetLength = sizeof(PRIVILEGE_SET);
return STATUS_BUFFER_TOO_SMALL;
@@ -1198,7 +1785,8 @@ NtAccessCheck(
&CapturedSecurityDescriptor);
if (!NT_SUCCESS(Status))
{
- DPRINT("Failed to capture the Security Descriptor\n");
+ DPRINT1("Failed to capture the Security Descriptor\n");
+ SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
ObDereferenceObject(Token);
return Status;
}
@@ -1206,23 +1794,45 @@ NtAccessCheck(
/* Check the captured security descriptor */
if (CapturedSecurityDescriptor == NULL)
{
- DPRINT("Security Descriptor is NULL\n");
+ DPRINT1("Security Descriptor is NULL\n");
+ SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
ObDereferenceObject(Token);
return STATUS_INVALID_SECURITY_DESCR;
}
/* Check security descriptor for valid owner and group */
- if (SepGetSDOwner(CapturedSecurityDescriptor) == NULL ||
- SepGetSDGroup(CapturedSecurityDescriptor) == NULL)
+ if (SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL ||
+ SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL)
{
- DPRINT("Security Descriptor does not have a valid group or owner\n");
+ DPRINT1("Security Descriptor does not have a valid group or owner\n");
SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
PreviousMode,
FALSE);
+ SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
ObDereferenceObject(Token);
return STATUS_INVALID_SECURITY_DESCR;
}
+ /* Capture the principal self SID if we have one */
+ if (PrincipalSelfSid)
+ {
+ Status = SepCaptureSid(PrincipalSelfSid,
+ PreviousMode,
+ PagedPool,
+ TRUE,
+ &CapturedPrincipalSelfSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to capture the principal self SID (Status 0x%08lx)\n", Status);
+ SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
+ PreviousMode,
+ FALSE);
+ SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
+ ObDereferenceObject(Token);
+ return Status;
+ }
+ }
+
/* Set up the subject context, and lock it */
SeCaptureSubjectContext(&SubjectSecurityContext);
@@ -1245,37 +1855,60 @@ NtAccessCheck(
if (DesiredAccess == 0)
{
- *GrantedAccess = PreviouslyGrantedAccess;
- *AccessStatus = STATUS_SUCCESS;
+ /*
+ * Propagate the access and status for the whole hierarchy
+ * of the list or just to single target object.
+ */
+ if (UseResultList)
+ {
+ for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
+ {
+ AccessStatus[ResultListIndex] = STATUS_SUCCESS;
+ GrantedAccess[ResultListIndex] = PreviouslyGrantedAccess;
+ }
+ }
+ else
+ {
+ *GrantedAccess = PreviouslyGrantedAccess;
+ *AccessStatus = STATUS_SUCCESS;
+ }
}
else
{
/* Now perform the access check */
- SepAccessCheck(CapturedSecurityDescriptor,
- Token,
- &SubjectSecurityContext.PrimaryToken,
- NULL,
- DesiredAccess,
- NULL,
- 0,
- PreviouslyGrantedAccess,
- GenericMapping,
- PreviousMode,
- FALSE,
- NULL,
- GrantedAccess,
- AccessStatus);
+ SepAccessCheckWorker(CapturedSecurityDescriptor,
+ Token,
+ &SubjectSecurityContext.PrimaryToken,
+ CapturedPrincipalSelfSid,
+ DesiredAccess,
+ CapturedObjectTypeList,
+ ObjectTypeListLength,
+ PreviouslyGrantedAccess,
+ GenericMapping,
+ PreviousMode,
+ UseResultList,
+ NULL,
+ GrantedAccess,
+ AccessStatus);
}
/* Release subject context and unlock the token */
SeReleaseSubjectContext(&SubjectSecurityContext);
SepReleaseTokenLock(Token);
+ /* Release the caputed principal self SID */
+ SepReleaseSid(CapturedPrincipalSelfSid,
+ PreviousMode,
+ TRUE);
+
/* Release the captured security descriptor */
SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
PreviousMode,
FALSE);
+ /* Release the object type list */
+ SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
+
/* Dereference the token */
ObDereferenceObject(Token);
@@ -1283,127 +1916,384 @@ NtAccessCheck(
return STATUS_SUCCESS;
}
+/* PUBLIC FUNCTIONS ***********************************************************/
+
/**
* @brief
- * Determines whether security access could be granted or not on
- * an object by the requestor who wants such access through type.
+ * Determines whether security access rights can be given to an object
+ * depending on the security descriptor and other security context
+ * entities, such as an owner.
*
* @param[in] SecurityDescriptor
- * A security descriptor with information data for auditing.
- *
- * @param[in] PrincipalSelfSid
- * A principal self user SID.
+ * Security descriptor of the object that is being accessed.
*
- * @param[in] ClientToken
- * A client access token.
+ * @param[in] SubjectSecurityContext
+ * The captured subject security context.
+ *
+ * @param[in] SubjectContextLocked
+ * If set to TRUE, the caller acknowledges that the subject context
+ * has already been locked by the caller himself. If set to FALSE,
+ * the function locks the subject context.
*
* @param[in] DesiredAccess
- * The desired access masks rights requested by the caller.
+ * Access right bitmask that the calling thread wants to acquire.
*
- * @param[in] ObjectTypeList
- * A list of object types.
+ * @param[in] PreviouslyGrantedAccess
+ * The access rights previously acquired in the past.
*
- * @param[in] ObjectTypeLength
- * The length size of the list.
+ * @param[out] Privileges
+ * The returned set of privileges.
*
* @param[in] GenericMapping
- * The generic mapping list of access masks rights.
- *
- * @param[in] PrivilegeSet
- * An array set of privileges.
+ * The generic mapping of access rights of an object type.
*
- * @param[in,out] PrivilegeSetLength
- * The length size of the array set of privileges.
+ * @param[in] AccessMode
+ * The processor request level mode.
*
* @param[out] GrantedAccess
- * The returned granted access rights.
+ * A list of granted access rights.
*
* @param[out] AccessStatus
- * The returned NTSTATUS code indicating the final results
- * of auditing.
+ * The returned status code specifying why access cannot be made
+ * onto an object (if said access is denied in the first place).
*
* @return
- * To be added...
+ * Returns TRUE if access onto the specific object is allowed, FALSE
+ * otherwise.
*/
-NTSTATUS
+BOOLEAN
NTAPI
-NtAccessCheckByType(
+SeAccessCheck(
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _In_ PSID PrincipalSelfSid,
- _In_ HANDLE ClientToken,
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
+ _In_ BOOLEAN SubjectContextLocked,
_In_ ACCESS_MASK DesiredAccess,
- _In_ POBJECT_TYPE_LIST ObjectTypeList,
- _In_ ULONG ObjectTypeLength,
+ _In_ ACCESS_MASK PreviouslyGrantedAccess,
+ _Out_ PPRIVILEGE_SET* Privileges,
_In_ PGENERIC_MAPPING GenericMapping,
- _In_ PPRIVILEGE_SET PrivilegeSet,
- _Inout_ PULONG PrivilegeSetLength,
+ _In_ KPROCESSOR_MODE AccessMode,
_Out_ PACCESS_MASK GrantedAccess,
_Out_ PNTSTATUS AccessStatus)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ BOOLEAN ret;
+
+ PAGED_CODE();
+
+ /* Check if this is kernel mode */
+ if (AccessMode == KernelMode)
+ {
+ /* Check if kernel wants everything */
+ if (DesiredAccess & MAXIMUM_ALLOWED)
+ {
+ /* Give it */
+ *GrantedAccess = GenericMapping->GenericAll;
+ *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
+ *GrantedAccess |= PreviouslyGrantedAccess;
+ }
+ else
+ {
+ /* Give the desired and previous access */
+ *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
+ }
+
+ /* Success */
+ *AccessStatus = STATUS_SUCCESS;
+ return TRUE;
+ }
+
+ /* Check if we didn't get an SD */
+ if (!SecurityDescriptor)
+ {
+ /* Automatic failure */
+ *AccessStatus = STATUS_ACCESS_DENIED;
+ return FALSE;
+ }
+
+ /* Check for invalid impersonation */
+ if ((SubjectSecurityContext->ClientToken) &&
+ (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
+ {
+ *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
+ return FALSE;
+ }
+
+ /* Acquire the lock if needed */
+ if (!SubjectContextLocked)
+ SeLockSubjectContext(SubjectSecurityContext);
+
+ /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
+ if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
+ {
+ PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
+ SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
+
+ if (SepTokenIsOwner(Token,
+ SecurityDescriptor,
+ FALSE))
+ {
+ if (DesiredAccess & MAXIMUM_ALLOWED)
+ PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
+ else
+ PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
+
+ DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
+ }
+ }
+
+ if (DesiredAccess == 0)
+ {
+ *GrantedAccess = PreviouslyGrantedAccess;
+ if (PreviouslyGrantedAccess == 0)
+ {
+ DPRINT1("Request for zero access to an object. Denying.\n");
+ *AccessStatus = STATUS_ACCESS_DENIED;
+ ret = FALSE;
+ }
+ else
+ {
+ *AccessStatus = STATUS_SUCCESS;
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ /* Call the internal function */
+ ret = SepAccessCheckWorker(SecurityDescriptor,
+ SubjectSecurityContext->ClientToken,
+ SubjectSecurityContext->PrimaryToken,
+ NULL,
+ DesiredAccess,
+ NULL,
+ 0,
+ PreviouslyGrantedAccess,
+ GenericMapping,
+ AccessMode,
+ FALSE,
+ Privileges,
+ GrantedAccess,
+ AccessStatus);
+ }
+
+ /* Release the lock if needed */
+ if (!SubjectContextLocked)
+ SeUnlockSubjectContext(SubjectSecurityContext);
+
+ return ret;
}
/**
* @brief
- * Determines whether security access could be granted or not on
- * an object by the requestor who wants such access through
- * type list.
+ * Determines whether security access rights can be given to an object
+ * depending on the security descriptor. Unlike the regular access check
+ * procedure in the NT kernel, the fast traverse check is a faster way
+ * to quickly check if access can be made into an object.
*
* @param[in] SecurityDescriptor
- * A security descriptor with information data for auditing.
- *
- * @param[in] PrincipalSelfSid
- * A principal self user SID.
+ * Security descriptor of the object that is being accessed.
*
- * @param[in] ClientToken
- * A client access token.
+ * @param[in] AccessState
+ * An access state to determine if the access token in the current
+ * security context of the object is an restricted token.
*
* @param[in] DesiredAccess
- * The desired access masks rights requested by the caller.
- *
- * @param[in] ObjectTypeList
- * A list of object types.
- *
- * @param[in] ObjectTypeLength
- * The length size of the list.
- *
- * @param[in] GenericMapping
- * The generic mapping list of access masks rights.
- *
- * @param[in] PrivilegeSet
- * An array set of privileges.
- *
- * @param[in,out] PrivilegeSetLength
- * The length size of the array set of privileges.
- *
- * @param[out] GrantedAccess
- * The returned granted access rights.
+ * The access right bitmask where the calling thread wants to acquire.
*
- * @param[out] AccessStatus
- * The returned NTSTATUS code indicating the final results
- * of auditing.
+ * @param[in] AccessMode
+ * Process level request mode.
*
* @return
- * To be added...
+ * Returns TRUE if access onto the specific object is allowed, FALSE
+ * otherwise.
+ */
+BOOLEAN
+NTAPI
+SeFastTraverseCheck(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ PACCESS_STATE AccessState,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ KPROCESSOR_MODE AccessMode)
+{
+ PACL Dacl;
+ ULONG AceIndex;
+ PKNOWN_ACE Ace;
+
+ PAGED_CODE();
+
+ ASSERT(AccessMode != KernelMode);
+
+ if (SecurityDescriptor == NULL)
+ return FALSE;
+
+ /* Get DACL */
+ Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
+ /* If no DACL, grant access */
+ if (Dacl == NULL)
+ return TRUE;
+
+ /* No ACE -> Deny */
+ if (!Dacl->AceCount)
+ return FALSE;
+
+ /* Can't perform the check on restricted token */
+ if (AccessState->Flags & TOKEN_IS_RESTRICTED)
+ return FALSE;
+
+ /* Browse the ACEs */
+ for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL));
+ AceIndex < Dacl->AceCount;
+ AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize))
+ {
+ if (Ace->Header.AceFlags & INHERIT_ONLY_ACE)
+ continue;
+
+ /* If access-allowed ACE */
+ if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
+ {
+ /* Check if all accesses are granted */
+ if (!(Ace->Mask & DesiredAccess))
+ continue;
+
+ /* Check SID and grant access if matching */
+ if (RtlEqualSid(SeWorldSid, &(Ace->SidStart)))
+ return TRUE;
+ }
+ /* If access-denied ACE */
+ else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE)
+ {
+ /* Here, only check if it denies any access wanted and deny if so */
+ if (Ace->Mask & DesiredAccess)
+ return FALSE;
+ }
+ }
+
+ /* Faulty, deny */
+ return FALSE;
+}
+
+/* SYSTEM CALLS ***************************************************************/
+
+/**
+ * @brief
+ * Determines whether security access can be granted to a client
+ * that requests such access on an object.
+ *
+ * @remarks
+ * For more documentation details about the parameters and
+ * overall function behavior, see SepAccessCheck.
*/
NTSTATUS
NTAPI
-NtAccessCheckByTypeResultList(
+NtAccessCheck(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ HANDLE ClientToken,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ PGENERIC_MAPPING GenericMapping,
+ _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
+ _Inout_ PULONG PrivilegeSetLength,
+ _Out_ PACCESS_MASK GrantedAccess,
+ _Out_ PNTSTATUS AccessStatus)
+{
+ PAGED_CODE();
+
+ /* Invoke the internal function to do the job */
+ return SepAccessCheck(SecurityDescriptor,
+ ClientToken,
+ NULL,
+ DesiredAccess,
+ GenericMapping,
+ PrivilegeSet,
+ PrivilegeSetLength,
+ NULL,
+ 0,
+ FALSE,
+ GrantedAccess,
+ AccessStatus);
+}
+
+/**
+ * @brief
+ * Determines whether security access can be granted to a client
+ * that requests such access on the object type list. The access
+ * is either granted or denied for the whole object hierarchy
+ * in the list.
+ *
+ * @remarks
+ * For more documentation details about the parameters and
+ * overall function behavior, see SepAccessCheck.
+ */
+NTSTATUS
+NTAPI
+NtAccessCheckByType(
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _In_ PSID PrincipalSelfSid,
+ _In_opt_ PSID PrincipalSelfSid,
_In_ HANDLE ClientToken,
_In_ ACCESS_MASK DesiredAccess,
- _In_ POBJECT_TYPE_LIST ObjectTypeList,
- _In_ ULONG ObjectTypeLength,
+ _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
_In_ PGENERIC_MAPPING GenericMapping,
- _In_ PPRIVILEGE_SET PrivilegeSet,
+ _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
_Inout_ PULONG PrivilegeSetLength,
_Out_ PACCESS_MASK GrantedAccess,
_Out_ PNTSTATUS AccessStatus)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PAGED_CODE();
+
+ /* Invoke the internal function to do the job */
+ return SepAccessCheck(SecurityDescriptor,
+ ClientToken,
+ PrincipalSelfSid,
+ DesiredAccess,
+ GenericMapping,
+ PrivilegeSet,
+ PrivilegeSetLength,
+ ObjectTypeList,
+ ObjectTypeListLength,
+ FALSE,
+ GrantedAccess,
+ AccessStatus);
+}
+
+/**
+ * @brief
+ * Determines whether security access can be granted to a client
+ * that requests such access on the object type list. Unlike the
+ * NtAccessCheckByType variant, this function will grant or deny
+ * access to each individual object and sub-object in the list.
+ *
+ * @remarks
+ * For more documentation details about the parameters and
+ * overall function behavior, see SepAccessCheck.
+ */
+NTSTATUS
+NTAPI
+NtAccessCheckByTypeResultList(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_opt_ PSID PrincipalSelfSid,
+ _In_ HANDLE ClientToken,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ PGENERIC_MAPPING GenericMapping,
+ _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
+ _Inout_ PULONG PrivilegeSetLength,
+ _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,
+ _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus)
+{
+ PAGED_CODE();
+
+ /* Invoke the internal function to do the job */
+ return SepAccessCheck(SecurityDescriptor,
+ ClientToken,
+ PrincipalSelfSid,
+ DesiredAccess,
+ GenericMapping,
+ PrivilegeSet,
+ PrivilegeSetLength,
+ ObjectTypeList,
+ ObjectTypeListLength,
+ TRUE,
+ GrantedAccess,
+ AccessStatus);
}
/* EOF */
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e38f4c2b360e40e918da9…
commit e38f4c2b360e40e918da94cf8fe7245fb9433746
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Wed Jun 21 17:52:47 2023 +0200
Commit: unknown <george.bisoc(a)reactos.org>
CommitDate: Tue Aug 22 17:54:17 2023 +0200
[NTOS:SE] Implement object type list utilities
This implements various private kernel routines for object type list management
needed for access check code infrastructure. In addition, update the code documentation
and add missing comments.
---
ntoskrnl/se/objtype.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 298 insertions(+), 23 deletions(-)
diff --git a/ntoskrnl/se/objtype.c b/ntoskrnl/se/objtype.c
index 24af8fff4f0..b459c2dc172 100644
--- a/ntoskrnl/se/objtype.c
+++ b/ntoskrnl/se/objtype.c
@@ -3,6 +3,7 @@
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Security object type list support routines
* COPYRIGHT: Copyright Timo Kreuzer <timo.kreuzer(a)reactos.org>
+ * Copyright 2023 George Bișoc <george.bisoc(a)reactos.org>
*/
/* INCLUDES *******************************************************************/
@@ -11,78 +12,351 @@
#define NDEBUG
#include <debug.h>
-/* PRIVATE FUNCTIONS ***********************************************************/
+/* PRIVATE FUNCTIONS **********************************************************/
/**
* @brief
- * Captures a list of object types.
+ * Validates a list of object types passed from user mode,
+ * ensuring the following conditions are met for a valid
+ * list:
+ *
+ * - The list must not be too big and it can be read
+ * - Each object must have a valid level
+ * - The level hierarchy between objects has to be consistent
+ * (e.g. a root cannot have a level 2 subordinate object)
+ * - The list must have only one root and it must be in the
+ * first position
+ * - Each object type GUID can be read and captured
*
* @param[in] ObjectTypeList
- * An existing list of object types.
+ * A pointer to an object type list of which the elements
+ * are being validated.
*
* @param[in] ObjectTypeListLength
- * The length size of the list.
+ * The length of the list, representing the number of object
+ * elements in that list.
+ *
+ * @return
+ * Returns STATUS_SUCCESS if the list has been validated and it
+ * contains valid objects. STATUS_INVALID_PARAMETER is returned
+ * if the list is not valid. Otherwise a NTSTATUS code is returned.
+ */
+static
+NTSTATUS
+SepValidateObjectTypeList(
+ _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength)
+{
+ PGUID ObjectTypeGuid;
+ ULONG ObjectTypeIndex;
+ USHORT Level, PrevLevel;
+ SIZE_T Size;
+
+ /* Ensure we do not hit an integer overflow */
+ Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST);
+ if (Size == 0)
+ {
+ DPRINT1("The object type list is too big, integer overflow alert!\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ _SEH2_TRY
+ {
+ /* Ensure we can actually read from that list */
+ ProbeForRead(ObjectTypeList, Size, sizeof(ULONG));
+
+ /* Begin looping for each object from the list */
+ for (ObjectTypeIndex = 0;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ /* Get the level of this object and check for validity */
+ Level = ObjectTypeList[ObjectTypeIndex].Level;
+ if (Level > ACCESS_MAX_LEVEL)
+ {
+ DPRINT1("Invalid object level found (level %u, at index %lu)\n", Level, ObjectTypeIndex);
+ _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
+ }
+
+ /* Are we past the first position in the list? */
+ if (ObjectTypeIndex != 0)
+ {
+ /* Ensure that we do not have two object roots */
+ if (Level == ACCESS_OBJECT_GUID)
+ {
+ DPRINT1("This list has two roots (at index %lu)\n", ObjectTypeIndex);
+ _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
+ }
+
+ /*
+ * Ensure the current level is consistent with the prior level.
+ * That means, if the previous object is the root (denoted by the
+ * level as ACCESS_OBJECT_GUID aka 0) the current object must
+ * be a child of the parent which is the root (also called a
+ * property set). Whereas a property is a sibling of the
+ * child, the property set.
+ */
+ if (Level > PrevLevel + 1)
+ {
+ DPRINT1("The object levels are not consistent (current level %u, previous level %u, at index %lu)\n",
+ Level, PrevLevel, ObjectTypeIndex);
+ _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
+ }
+ }
+ else
+ {
+ /* This is the first position so the object must be the root */
+ if (Level != ACCESS_OBJECT_GUID)
+ {
+ DPRINT1("The object is not the root at first index!\n");
+ _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
+ }
+ }
+
+ /* Get the object type and check that we can read from it */
+ ObjectTypeGuid = ObjectTypeList[ObjectTypeIndex].ObjectType;
+ ProbeForRead(ObjectTypeGuid, sizeof(GUID), sizeof(ULONG));
+
+ /*
+ * Cache the level, we need it to ensure the levels between
+ * the previous and the next object are consistent with each other.
+ */
+ PrevLevel = Level;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * @brief
+ * Compares two object type GUIDs for equality.
+ *
+ * @param[in] Guid1
+ * A pointer to the first object type GUID.
+ *
+ * @param[in] Guid2
+ * A pointer to the second object type GUID.
+ *
+ * @return
+ * Returns TRUE if both GUIDs are equal, FALSE otherwise.
+ */
+static
+BOOLEAN
+SepIsEqualObjectTypeGuid(
+ _In_ CONST GUID *Guid1,
+ _In_ CONST GUID *Guid2)
+{
+ return RtlCompareMemory(Guid1, Guid2, sizeof(GUID)) == sizeof(GUID);
+}
+
+/* PUBLIC FUNCTIONS ************************************************************/
+
+/**
+ * @brief
+ * Captures an object type GUID from an object
+ * access control entry (ACE).
+ *
+ * @param[in] Ace
+ * A pointer to an access control entry, of which
+ * the object type GUID is to be captured from.
+ *
+ * @param[in] IsAceDenied
+ * If set to TRUE, the function will capture the
+ * GUID from a denied object ACE, otherwise from
+ * the allowed object ACE.
+ *
+ * @return
+ * Returns a pointer to an object type GUID, otherwise
+ * NULL is returned if the target ACE does not have
+ * an object type GUID.
+ */
+PGUID
+SepGetObjectTypeGuidFromAce(
+ _In_ PACE Ace,
+ _In_ BOOLEAN IsAceDenied)
+{
+ PGUID ObjectTypeGuid = NULL;
+
+ PAGED_CODE();
+
+ /* This Ace must not be NULL */
+ ASSERT(Ace);
+
+ /* Grab the GUID based on the object type ACE header */
+ ObjectTypeGuid = IsAceDenied ? (PGUID)&((PACCESS_DENIED_OBJECT_ACE)Ace)->ObjectType :
+ (PGUID)&((PACCESS_ALLOWED_OBJECT_ACE)Ace)->ObjectType;
+ return ObjectTypeGuid;
+}
+
+/**
+ * @brief
+ * Searches for an object type GUID if it exists
+ * on an object type list.
+ *
+ * @param[in] ObjectTypeList
+ * A pointer to an object type list.
+ *
+ * @param[in] ObjectTypeListLength
+ * The length of the list, representing the number
+ * of object elements in that list.
+ *
+ * @param[in] ObjectTypeGuid
+ * A pointer to an object type GUID to search in the
+ * list of interest.
+ *
+ * @param[out] ObjectIndex
+ * If the function found the target GUID, the function
+ * returns a pointer to the object index location to
+ * this parameter.
+ *
+ * @return
+ * Returns TRUE if the object type GUID of interest exists
+ * in the target list, FALSE otherwise.
+ */
+BOOLEAN
+SepObjectTypeGuidInList(
+ _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ PGUID ObjectTypeGuid,
+ _Out_ PULONG ObjectIndex)
+{
+ ULONG ObjectTypeIndex;
+ GUID ObjectTypeGuidToSearch;
+
+ PAGED_CODE();
+
+ /* Loop over the object elements */
+ for (ObjectTypeIndex = 0;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ /* Is this the object we are searching for? */
+ ObjectTypeGuidToSearch = ObjectTypeList[ObjectTypeIndex].ObjectTypeGuid;
+ if (SepIsEqualObjectTypeGuid(ObjectTypeGuid, &ObjectTypeGuidToSearch))
+ {
+ /* Return the indext of that object to caller */
+ *ObjectIndex = ObjectTypeIndex;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ * @brief
+ * Captures a list of object types and converts it to
+ * an internal form for use by the kernel. The list
+ * is validated before its data is copied.
+ *
+ * @param[in] ObjectTypeList
+ * A pointer to a list of object types passed from
+ * UM to be captured.
+ *
+ * @param[in] ObjectTypeListLength
+ * The length size of the list. This length represents
+ * the number of object elements in that list.
*
* @param[in] PreviousMode
- * Processor access level mode.
+ * Processor access level mode. This has to be set to
+ * UserMode as object type access check is not supported
+ * in the kernel.
*
* @param[out] CapturedObjectTypeList
- * The captured list of object types.
+ * A pointer to a returned captured list of object types.
*
* @return
* Returns STATUS_SUCCESS if the list of object types has been captured
* successfully. STATUS_INVALID_PARAMETER is returned if the caller hasn't
- * supplied a buffer list of object types. STATUS_INSUFFICIENT_RESOURCES
- * is returned if pool memory allocation for the captured list has failed.
+ * supplied a buffer list of object types or the list is invalid.
+ * STATUS_INSUFFICIENT_RESOURCES is returned if pool memory allocation
+ * for the captured list has failed.
*/
NTSTATUS
SeCaptureObjectTypeList(
_In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
_In_ ULONG ObjectTypeListLength,
_In_ KPROCESSOR_MODE PreviousMode,
- _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList)
+ _Out_ POBJECT_TYPE_LIST_INTERNAL *CapturedObjectTypeList)
{
+ NTSTATUS Status;
+ ULONG ObjectTypeIndex;
SIZE_T Size;
+ PGUID ObjectTypeGuid;
+ POBJECT_TYPE_LIST_INTERNAL InternalTypeList;
+
+ PAGED_CODE();
+ /* We do not support that in the kernel */
if (PreviousMode == KernelMode)
{
return STATUS_NOT_IMPLEMENTED;
}
+ /* No count elements of objects means no captured list for you */
if (ObjectTypeListLength == 0)
{
*CapturedObjectTypeList = NULL;
return STATUS_SUCCESS;
}
+ /* Check if the caller supplied a list since we have the count of elements */
if (ObjectTypeList == NULL)
{
+ DPRINT1("The caller did not provide a list of object types!\n");
return STATUS_INVALID_PARAMETER;
}
- /* Calculate the list size and check for integer overflow */
- Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST);
- if (Size == 0)
+ /* Validate that list before we copy contents from it */
+ Status = SepValidateObjectTypeList(ObjectTypeList, ObjectTypeListLength);
+ if (!NT_SUCCESS(Status))
{
- return STATUS_INVALID_PARAMETER;
+ DPRINT1("SepValidateObjectTypeList failed (Status 0x%08lx)\n", Status);
+ return Status;
}
/* Allocate a new list */
- *CapturedObjectTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA);
- if (*CapturedObjectTypeList == NULL)
+ Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST_INTERNAL);
+ InternalTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA);
+ if (InternalTypeList == NULL)
{
+ DPRINT1("Failed to allocate pool memory for the object type list!\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
_SEH2_TRY
{
- ProbeForRead(ObjectTypeList, Size, sizeof(ULONG));
- RtlCopyMemory(*CapturedObjectTypeList, ObjectTypeList, Size);
+ /* Loop for every object element, data was already probed */
+ for (ObjectTypeIndex = 0;
+ ObjectTypeIndex < ObjectTypeListLength;
+ ObjectTypeIndex++)
+ {
+ /* Copy the object type GUID */
+ ObjectTypeGuid = ObjectTypeList[ObjectTypeIndex].ObjectType;
+ InternalTypeList[ObjectTypeIndex].ObjectTypeGuid = *ObjectTypeGuid;
+
+ /* Copy the object hierarchy level */
+ InternalTypeList[ObjectTypeIndex].Level = ObjectTypeList[ObjectTypeIndex].Level;
+
+ /* Initialize the access check rights */
+ InternalTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights = 0;
+ InternalTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights = 0;
+ InternalTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights = 0;
+ }
+
+ /* Give the captured list to caller */
+ *CapturedObjectTypeList = InternalTypeList;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- ExFreePoolWithTag(*CapturedObjectTypeList, TAG_SEPA);
- *CapturedObjectTypeList = NULL;
+ ExFreePoolWithTag(InternalTypeList, TAG_SEPA);
+ InternalTypeList = NULL;
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
@@ -99,17 +373,18 @@ SeCaptureObjectTypeList(
*
* @param[in] PreviousMode
* Processor access level mode.
- *
- * @return
- * Nothing.
*/
VOID
SeReleaseObjectTypeList(
- _In_ _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList,
+ _In_ _Post_invalid_ POBJECT_TYPE_LIST_INTERNAL CapturedObjectTypeList,
_In_ KPROCESSOR_MODE PreviousMode)
{
+ PAGED_CODE();
+
if ((PreviousMode != KernelMode) && (CapturedObjectTypeList != NULL))
+ {
ExFreePoolWithTag(CapturedObjectTypeList, TAG_SEPA);
+ }
}
/* EOF */