Пример #1
0
        /// <summary>
        /// Adds or replaces groups in the specified Authz Client Context.
        /// </summary>
        /// <remarks>This method invokes AuthzModifySids, modifying the groups
        /// using AUTHZ_SID_OPERATION_REPLACE. This ensures that a group that
        /// already exists is retained and the ones not present are added</remarks>
        /// <param name="hAuthzClientContext">Handle to the Authz Client Context to be modified</param>
        /// <returns>Win32Error.ERROR_SUCCESS on success and Win32 error code otherwise.</returns>
        public int ApplyGroups(AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext)
        {
            var toBeFreed        = new List <SafeHGlobalHandle>();
            var sidAndAttributes = new List <NativeMethods.SID_AND_ATTRIBUTES>(this.Count);
            var sidOps           = new NativeMethods.AuthzSIDOperation[this.Count];

            foreach (var sid in this)
            {
                byte[] rawSid = new byte[sid.BinaryLength];
                sid.GetBinaryForm(rawSid, 0);

                SafeHGlobalHandle safesid = SafeHGlobalHandle.AllocHGlobal(rawSid);
                toBeFreed.Add(safesid);

                sidAndAttributes.Add(new NativeMethods.SID_AND_ATTRIBUTES(safesid.ToIntPtr(),
                                                                          NativeMethods.GroupAddtibute.Enabled));
            }

            SafeHGlobalHandle tokenGroups = SafeHGlobalHandle.AllocHGlobal(Marshal.SizeOf(typeof(ULONG)),
                                                                           sidAndAttributes,
                                                                           sidAndAttributes.Count);

            Marshal.WriteInt32(tokenGroups.ToIntPtr(), sidAndAttributes.Count);

            for (int Idx = 0; Idx < this.Count; ++Idx)
            {
                sidOps[Idx] = NativeMethods.AuthzSIDOperation.Replace;
            }

            if (!NativeMethods.AuthzModifySids(hAuthzClientContext,
                                               type == GroupType.User
                                               ? NativeMethods.AuthzContextInformationClass.AuthzContextInfoGroupsSids
                                               : NativeMethods.AuthzContextInformationClass.AuthzContextInfoDeviceSids,
                                               sidOps,
                                               tokenGroups.ToIntPtr()))
            {
                return(Marshal.GetLastWin32Error());
            }

            return(Win32Error.ERROR_SUCCESS);
        }
        /// <summary>
        /// Adds or replaces claims in the specified Authz Client Context.
        /// </summary>
        /// <remarks>This method invokes AuthzModifyClaims, modifying the claims
        /// using AUTHZ_SECURITY_ATTRIBUTE_OPERATION_REPLACE. This ensures that
        /// the values of a claims that already exists are replaces and the ones
        /// not present are added.</remarks>
        /// <param name="handleClientContext">Handle to the Authz Client Context to be modified</param>
        /// <returns>Win32Error.ERROR_SUCCESS on success and Win32 error code otherwise.</returns>
        public int ApplyClaims(AUTHZ_CLIENT_CONTEXT_HANDLE handleClientContext)
        {
            NativeMethods.AuthzSecurityAttributeOperation[] claimOps = null;
            var claims = new List <NativeMethods.AUTHZ_SECURITY_ATTRIBUTE_V1>(this.Count);

            foreach (var claim in this)
            {
                //
                // If all of the value specified turned out invalid, ignore the claim altogether.
                //
                if (claim.Value.ValueCount == 0)
                {
                    continue;
                }

                var attribute = new NativeMethods.AUTHZ_SECURITY_ATTRIBUTE_V1();

                attribute.Name       = claim.Key;
                attribute.Flags      = 0;
                attribute.Values     = claim.Value.RawValues.ToIntPtr();
                attribute.ValueCount = claim.Value.ValueCount;

                switch (claim.Value.ValueType)
                {
                case ClaimValueType.Integer:
                {
                    Debug.Assert(attribute.ValueCount == 1);
                    attribute.Type = NativeMethods.AuthzSecurityAttributeValueType.Int;
                    break;
                }

                case ClaimValueType.Boolean:
                {
                    Debug.Assert(attribute.ValueCount == 1);
                    attribute.Type = NativeMethods.AuthzSecurityAttributeValueType.Boolean;
                    break;
                }

                case ClaimValueType.String:
                {
                    Debug.Assert(attribute.ValueCount == 1);
                    goto case ClaimValueType.MultiValuedString;
                }

                case ClaimValueType.MultiValuedString:
                {
                    attribute.Type = NativeMethods.AuthzSecurityAttributeValueType.String;
                    break;
                }
                }

                claims.Add(attribute);
            }

            var claimInfo = new NativeMethods.AUTHZ_SECURITY_ATTRIBUTES_INFORMATION();

            claimInfo.Version        = 1; // AUTHZ_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1
            claimInfo.Reserved       = 0;
            claimInfo.AttributeCount = (ULONG)claims.Count;

            SafeHGlobalHandle v1Attributes = SafeHGlobalHandle.InvalidHandle;

            if (claimInfo.AttributeCount != 0)
            {
                v1Attributes = SafeHGlobalHandle.AllocHGlobal(claims);

                claimOps = new NativeMethods.AuthzSecurityAttributeOperation[claimInfo.AttributeCount];
                for (ULONG Idx = 0; Idx < claimInfo.AttributeCount; ++Idx)
                {
                    claimOps[Idx] = NativeMethods.AuthzSecurityAttributeOperation.Replace;
                }
            }

            claimInfo.pAttributeV1 = v1Attributes.ToIntPtr();

            if (!NativeMethods.AuthzModifyClaims(handleClientContext,
                                                 claimDefnType == ClaimDefinitionType.User
                                                 ? NativeMethods.AuthzContextInformationClass.AuthzContextInfoUserClaims
                                                 : NativeMethods.AuthzContextInformationClass.AuthzContextInfoDeviceClaims,
                                                 claimOps,
                                                 ref claimInfo))
            {
                return(Marshal.GetLastWin32Error());
            }

            return(Win32Error.ERROR_SUCCESS);
        }
        /// <summary>
        /// Computes the effective access permissions
        /// </summary>
        /// <param name="userSid">User account for which effective access rights are to be determined</param>
        /// <param name="deviceSid">Account to simulate the device where from the resource is being accessed</param>
        /// <param name="serverName">Target machine on which the resource</param>
        /// <param name="securityObjects">Security objects that affect that result of the access check</param>
        /// <returns>Dictionary of rights from NTFSAccess and the security object name that limits access to this
        /// permission</returns>
        Dictionary <NativeMethods.FileAccess, string> ComputeEffectiveAccessResult(
            string serverName,
            Dictionary <string, FileSecurityObject> securityObjects)
        {
            AUTHZ_CLIENT_CONTEXT_HANDLE userClientCtxt   = AUTHZ_CLIENT_CONTEXT_HANDLE.Zero;
            AUTHZ_CLIENT_CONTEXT_HANDLE deviceClientCtxt = AUTHZ_CLIENT_CONTEXT_HANDLE.Zero;
            AUTHZ_CLIENT_CONTEXT_HANDLE compoundCtxt     = AUTHZ_CLIENT_CONTEXT_HANDLE.Zero;

            try
            {
                var rpcInitInfo = new NativeMethods.AUTHZ_RPC_INIT_INFO_CLIENT();

                rpcInitInfo.version    = NativeMethods.AuthzRpcClientVersion.V1;
                rpcInitInfo.objectUuid = NativeMethods.AUTHZ_OBJECTUUID_WITHCAP;
                rpcInitInfo.protocol   = NativeMethods.RCP_OVER_TCP_PROTOCOL;
                rpcInitInfo.server     = serverName;

                SafeAuthzRMHandle authzRM;

                SafeHGlobalHandle pRpcInitInfo = SafeHGlobalHandle.AllocHGlobalStruct(rpcInitInfo);
                if (!NativeMethods.AuthzInitializeRemoteResourceManager(pRpcInitInfo.ToIntPtr(), out authzRM))
                {
                    int error = Marshal.GetLastWin32Error();

                    if (error != Win32Error.EPT_S_NOT_REGISTERED)
                    {
                        throw new Win32Exception(error);
                    }

                    //
                    // As a fallback we do AuthzInitializeResourceManager. But the results can be inaccurate.
                    //
                    Helper.LogWarning("The effective rights can only be computed based on group membership on this" +
                                      " computer. For more accurate results, calculate effective access rights on " +
                                      "the target computer.", true);

                    if (!NativeMethods.AuthzInitializeResourceManager(
                            NativeMethods.AuthzResourceManagerFlags.NO_AUDIT,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            "EffectiveAccessCheck",
                            out authzRM))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }

                byte[] rawSid = new byte[userSid.BinaryLength];
                userSid.GetBinaryForm(rawSid, 0);

                //
                // Create an AuthZ context based on the user account
                //
                if (!NativeMethods.AuthzInitializeContextFromSid(NativeMethods.AuthzInitFlags.Default,
                                                                 rawSid,
                                                                 authzRM,
                                                                 PLARGE_INTEGER.Zero,
                                                                 Win32.LUID.NullLuid,
                                                                 LPVOID.Zero,
                                                                 out userClientCtxt))
                {
                    Win32Exception win32Expn = new Win32Exception(Marshal.GetLastWin32Error());

                    if (win32Expn.NativeErrorCode != Win32Error.RPC_S_SERVER_UNAVAILABLE)
                    {
                        throw win32Expn;
                    }

                    Helper.LogWarning(string.Format(CultureInfo.CurrentCulture,
                                                    "{0}. Please enable the inward firewall rule: Netlogon Service " +
                                                    "Authz(RPC), on the target machine and try again.", win32Expn.Message),
                                      true);
                    return(null);
                }

                //
                // Create an Authz Compound context based on the userClientCtxt and the device account
                //
                if (deviceSid != null)
                {
                    rawSid = new byte[deviceSid.BinaryLength];
                    deviceSid.GetBinaryForm(rawSid, 0);

                    if (!NativeMethods.AuthzInitializeContextFromSid(NativeMethods.AuthzInitFlags.Default,
                                                                     rawSid,
                                                                     authzRM,
                                                                     PLARGE_INTEGER.Zero,
                                                                     Win32.LUID.NullLuid,
                                                                     LPVOID.Zero,
                                                                     out deviceClientCtxt))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    if (!NativeMethods.AuthzInitializeCompoundContext(userClientCtxt,
                                                                      deviceClientCtxt,
                                                                      out compoundCtxt))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    compoundCtxt = userClientCtxt;
                }

                //
                // Modify user claims in the Authz context
                //
                if (userClaims.Count != 0)
                {
                    int result = userClaims.ApplyClaims(compoundCtxt);

                    if (result != Win32Error.ERROR_SUCCESS)
                    {
                        throw new Win32Exception(result);
                    }
                }

                //
                // Modify device claims in the Authz context
                //
                if (deviceClaims.Count != 0)
                {
                    int result = deviceClaims.ApplyClaims(compoundCtxt);

                    if (result != Win32Error.ERROR_SUCCESS)
                    {
                        throw new Win32Exception(result);
                    }
                }

                //
                // Include additional group membership in the Authz context
                //
                if (userGroups.Count != 0)
                {
                    int result = userGroups.ApplyGroups(compoundCtxt);

                    if (result != Win32Error.ERROR_SUCCESS)
                    {
                        throw new Win32Exception(result);
                    }
                }

                //
                // Include additional device membership in the Authz context
                //
                if (deviceGroups.Count != 0)
                {
                    int result = deviceGroups.ApplyGroups(compoundCtxt);

                    if (result != Win32Error.ERROR_SUCCESS)
                    {
                        throw new Win32Exception(result);
                    }
                }

                PACCESS_MASK[] grantedAccess = new PACCESS_MASK[securityObjects.Count];
                PDWORD[]       errorSecObj   = new PACCESS_MASK[securityObjects.Count];

                try
                {
                    uint Index = 0;
                    foreach (var securityObject in securityObjects)
                    {
                        NativeMethods.AUTHZ_ACCESS_REQUEST request = new NativeMethods.AUTHZ_ACCESS_REQUEST();
                        request.DesiredAccess        = NativeMethods.StdAccess.MAXIMUM_ALLOWED;
                        request.PrincipalSelfSid     = null;
                        request.ObjectTypeList       = POBJECT_TYPE_LIST.Zero;
                        request.ObjectTypeListLength = 0;
                        request.OptionalArguments    = LPVOID.Zero;

                        var reply = new NativeMethods.AUTHZ_ACCESS_REPLY();
                        reply.ResultListLength      = 1;
                        reply.SaclEvaluationResults = PDWORD.Zero;
                        reply.GrantedAccessMask     = grantedAccess[Index] = Marshal.AllocHGlobal(sizeof(uint));
                        reply.Error = errorSecObj[Index] = Marshal.AllocHGlobal(sizeof(uint));

                        byte[] rawSD = new byte[securityObject.Value.securityDescriptor.BinaryLength];
                        securityObject.Value.securityDescriptor.GetBinaryForm(rawSD, 0);

                        //
                        // If a security object has the AppliesTo predicate, then we are processing a Central Access
                        // Rule. If the AppliesTo predicate is not satisfied, we do not have to bother performing an
                        // access check on the Central Access Rule's DACL.
                        //
                        if (securityObject.Value.appliesTo != null)
                        {
                            byte[] rawSD2 = new byte[securityObject.Value.appliesTo.BinaryLength];
                            securityObject.Value.appliesTo.GetBinaryForm(rawSD2, 0);

                            if (!NativeMethods.AuthzAccessCheck(NativeMethods.AuthzACFlags.None,
                                                                compoundCtxt,
                                                                ref request,
                                                                AUTHZ_AUDIT_EVENT_HANDLE.Zero,
                                                                rawSD2,
                                                                null,
                                                                0,
                                                                ref reply,
                                                                AUTHZ_ACCESS_CHECK_RESULTS_HANDLE.Zero))
                            {
                                throw new Win32Exception(Marshal.GetLastWin32Error());
                            }

                            //
                            // The applies to DACL is D:(XA;;FR;;;<user-sid>;<resource condition>).
                            // Check if we were successful in acquiring this particular access
                            //
                            var whatWasGranted = (NativeMethods.FileAccess)Marshal.ReadInt32(grantedAccess[Index]);
                            if ((NativeMethods.FileAccess.ReadData & whatWasGranted) == 0)
                            {
                                securityObject.Value.result.grantedAccess = NativeMethods.FileAccess.CategoricalAll;
                                continue;
                            }
                        }

                        if (!NativeMethods.AuthzAccessCheck(NativeMethods.AuthzACFlags.None,
                                                            compoundCtxt,
                                                            ref request,
                                                            AUTHZ_AUDIT_EVENT_HANDLE.Zero,
                                                            rawSD,
                                                            null,
                                                            0,
                                                            ref reply,
                                                            AUTHZ_ACCESS_CHECK_RESULTS_HANDLE.Zero))
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }

                        securityObject.Value.result.grantedAccess = (NativeMethods.FileAccess)
                                                                    Marshal.ReadInt32(grantedAccess[Index]);
                        ++Index;
                    }

                    //
                    // Build the effective permission results
                    //
                    var accessLimitedBy = new Dictionary <NativeMethods.FileAccess, string>();

                    foreach (var permission in NTFSAccess)
                    {
                        foreach (var securityObject in securityObjects)
                        {
                            if (!accessLimitedBy.ContainsKey(permission.Key))
                            {
                                accessLimitedBy.Add(permission.Key, "");
                            }

                            if ((permission.Key & securityObject.Value.result.grantedAccess) != permission.Key)
                            {
                                if (!string.IsNullOrEmpty(accessLimitedBy[permission.Key]))
                                {
                                    accessLimitedBy[permission.Key] += ", ";
                                }

                                accessLimitedBy[permission.Key] += securityObject.Key;
                            }
                        }
                    }

                    return(accessLimitedBy);
                }
                finally
                {
                    for (int Index = 0; Index < grantedAccess.Length; ++Index)
                    {
                        Marshal.FreeHGlobal(grantedAccess[Index]);
                    }

                    for (int Index = 0; Index < errorSecObj.Length; ++Index)
                    {
                        Marshal.FreeHGlobal(errorSecObj[Index]);
                    }
                }
            }
            finally
            {
                if (userClientCtxt != AUTHZ_CLIENT_CONTEXT_HANDLE.Zero)
                {
                    NativeMethods.AuthzFreeContext(userClientCtxt);
                    userClientCtxt = AUTHZ_CLIENT_CONTEXT_HANDLE.Zero;
                }

                if (deviceClientCtxt != AUTHZ_CLIENT_CONTEXT_HANDLE.Zero)
                {
                    NativeMethods.AuthzFreeContext(deviceClientCtxt);
                    deviceClientCtxt = AUTHZ_CLIENT_CONTEXT_HANDLE.Zero;

                    if (compoundCtxt != AUTHZ_CLIENT_CONTEXT_HANDLE.Zero)
                    {
                        NativeMethods.AuthzFreeContext(compoundCtxt);
                        compoundCtxt = AUTHZ_CLIENT_CONTEXT_HANDLE.Zero;
                    }
                }
            }
        }