[RTL]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 31 Aug 2013 17:34:37 +0000 (17:34 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 31 Aug 2013 17:34:37 +0000 (17:34 +0000)
Implement RtlDefaultNpAcl, needed for giving a default security to named pipes. Makes Win2k3 kernel32 happy when one creates named pipes for SCM and so on.
Getting the SID of the caller is done as described in http://www.osronline.com/article.cfm?article=50 in "Extracting the SID from the Token".

svn path=/trunk/; revision=59928

reactos/lib/rtl/security.c

index 0171bec..9db3acf 100644 (file)
@@ -6,7 +6,7 @@
  * PROGRAMMER:        Eric Kohl
  */
 
-/* INCLUDES *****************************************************************/
+/* INCLUDES *******************************************************************/
 
 #include <rtl.h>
 #define NDEBUG
@@ -60,12 +60,160 @@ RtlpConvertToAutoInheritSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor,
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 
+/*
+ * @implemented
+ */
 NTSTATUS
 NTAPI
-RtlDefaultNpAcl(OUT PACL Acl)
+RtlDefaultNpAcl(OUT PACL *pAcl)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    HANDLE TokenHandle;
+    PTOKEN_OWNER OwnerSid;
+    ULONG ReturnLength = 0;
+    ULONG AclSize;
+    SID_IDENTIFIER_AUTHORITY NtAuthority    = {SECURITY_NT_AUTHORITY};
+    SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+
+    /*
+     * Temporary buffer large enough to hold a maximum of two SIDs.
+     * An alternative is to call RtlAllocateAndInitializeSid many times...
+     */
+    UCHAR SidBuffer[16];
+    PSID Sid = (PSID)&SidBuffer;
+
+    ASSERT(RtlLengthRequiredSid(2) == 16);
+
+    /* Initialize the user ACL pointer */
+    *pAcl = NULL;
+
+    /*
+     * Try to retrieve the SID of the current owner. For that,
+     * we first attempt to get the current thread level token.
+     */
+    Status = NtOpenThreadToken(NtCurrentThread(),
+                               TOKEN_QUERY,
+                               TRUE,
+                               &TokenHandle);
+    if (Status == STATUS_NO_TOKEN)
+    {
+        /*
+         * No thread level token, so use the process level token.
+         * This is the common case since the only time a thread
+         * has a token is when it is impersonating.
+         */
+        Status = NtOpenProcessToken(NtCurrentProcess(),
+                                    TOKEN_QUERY,
+                                    &TokenHandle);
+    }
+    /* Fail if we didn't succeed in retrieving a handle to the token */
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /*
+     * Retrieve the owner SID from the token.
+     */
+
+    /* Query the needed size... */
+    Status = NtQueryInformationToken(TokenHandle,
+                                     TokenOwner,
+                                     NULL, 0,
+                                     &ReturnLength);
+    /* ... so that we must fail with STATUS_BUFFER_TOO_SMALL error */
+    if (Status != STATUS_BUFFER_TOO_SMALL) goto Cleanup1;
+
+    /* Allocate space for the owner SID */
+    OwnerSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength);
+    if (OwnerSid == NULL)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup1;
+    }
+
+    /* Retrieve the owner SID; we must succeed */
+    Status = NtQueryInformationToken(TokenHandle,
+                                     TokenOwner,
+                                     OwnerSid,
+                                     ReturnLength,
+                                     &ReturnLength);
+    if (!NT_SUCCESS(Status)) goto Cleanup2;
+
+    /*
+     * Allocate one ACL with 5 ACEs.
+     *
+     * NOTE: sizeof(ACE) == sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*)NULL)->SidStart)
+     * (see kernel32/client/debugger.c line 54).
+     */
+    AclSize = sizeof(ACL) +                     // Header
+              5 * sizeof(ACE /*ACCESS_ALLOWED_ACE*/) +  // 5 ACEs:
+              RtlLengthRequiredSid(1) +         // LocalSystem
+              RtlLengthRequiredSid(2) +         // Administrators
+              RtlLengthRequiredSid(1) +         // Anonymous
+              RtlLengthRequiredSid(1) +         // World
+              RtlLengthSid(OwnerSid->Owner);    // Owner
+
+    *pAcl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclSize);
+    if (*pAcl == NULL)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup2;
+    }
+
+    /*
+     * Build the ACL and add the five ACEs.
+     */
+    Status = RtlCreateAcl(*pAcl, AclSize, ACL_REVISION2);
+    ASSERT(NT_SUCCESS(Status));
+
+    /* Local System SID - Generic All */
+    Status = RtlInitializeSid(Sid, &NtAuthority, 1);
+    ASSERT(NT_SUCCESS(Status));
+    *RtlSubAuthoritySid(Sid, 0) = SECURITY_LOCAL_SYSTEM_RID;
+    Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, Sid);
+    ASSERT(NT_SUCCESS(Status));
+
+    /* Administrators SID - Generic All */
+    Status = RtlInitializeSid(Sid, &NtAuthority, 2);
+    ASSERT(NT_SUCCESS(Status));
+    *RtlSubAuthoritySid(Sid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
+    *RtlSubAuthoritySid(Sid, 1) = DOMAIN_ALIAS_RID_ADMINS;
+    Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, Sid);
+    ASSERT(NT_SUCCESS(Status));
+
+    /* Owner SID - Generic All */
+    RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_ALL, OwnerSid->Owner);
+    ASSERT(NT_SUCCESS(Status));
+
+    /* Anonymous SID - Generic Read */
+    Status = RtlInitializeSid(Sid, &NtAuthority, 1);
+    ASSERT(NT_SUCCESS(Status));
+    *RtlSubAuthoritySid(Sid, 0) = SECURITY_ANONYMOUS_LOGON_RID;
+    Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_READ, Sid);
+    ASSERT(NT_SUCCESS(Status));
+
+    /* World SID - Generic Read */
+    Status = RtlInitializeSid(Sid, &WorldAuthority, 1);
+    ASSERT(NT_SUCCESS(Status));
+    *RtlSubAuthoritySid(Sid, 0) = SECURITY_WORLD_RID;
+    Status = RtlAddAccessAllowedAce(*pAcl, ACL_REVISION2, GENERIC_READ, Sid);
+    ASSERT(NT_SUCCESS(Status));
+
+    /* If some problem happened, cleanup everything */
+    if (!NT_SUCCESS(Status))
+    {
+        RtlFreeHeap(RtlGetProcessHeap(), 0, *pAcl);
+        *pAcl = NULL;
+    }
+
+Cleanup2:
+    /* Get rid of the owner SID */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid);
+
+Cleanup1:
+    /* Close the token handle */
+    NtClose(TokenHandle);
+
+    /* Done */
+    return Status;
 }
 
 /*