2 * security.c: Security internal calls
5 * Sebastien Pouliot <sebastien@ximian.com>
7 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
14 #include <mono/metadata/assembly.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/image.h>
17 #include <mono/metadata/exception.h>
18 #include <mono/metadata/object-internals.h>
19 #include <mono/metadata/metadata-internals.h>
20 #include <mono/metadata/security.h>
21 #include <mono/io-layer/io-layer.h>
22 #include <mono/utils/strenc.h>
29 #ifndef PROTECTED_DACL_SECURITY_INFORMATION
30 #define PROTECTED_DACL_SECURITY_INFORMATION 0x80000000L
40 #include <sys/types.h>
47 #ifndef HAVE_GETGRGID_R
48 #warning Non-thread safe getgrgid being used!
50 #ifndef HAVE_GETGRNAM_R
51 #warning Non-thread safe getgrnam being used!
53 #ifndef HAVE_GETPWNAM_R
54 #warning Non-thread safe getpwnam being used!
56 #ifndef HAVE_GETPWUID_R
57 #warning Non-thread safe getpwuid being used!
60 #endif /* defined(__GNUC__) */
62 #endif /* not HOST_WIN32 */
65 /* internal functions - reuse driven */
69 /* ask a server to translate a SID into a textual representation */
71 GetSidName (gunichar2
*server
, PSID sid
, gint32
*size
)
73 gunichar2
*uniname
= NULL
;
76 SID_NAME_USE peUse
; /* out */
78 LookupAccountSid (server
, sid
, NULL
, &cchName
, NULL
,
81 if ((cchName
> 0) && (cchDomain
> 0)) {
82 gunichar2
*user
= g_malloc0 ((cchName
+ 1) * 2);
83 gunichar2
*domain
= g_malloc0 ((cchDomain
+ 1) * 2);
85 LookupAccountSid (server
, sid
, user
, &cchName
, domain
,
90 /* domain/machine name included (+ sepearator) */
91 *size
= cchName
+ cchDomain
+ 1;
92 uniname
= g_malloc0 ((*size
+ 1) * 2);
93 memcpy (uniname
, domain
, cchDomain
* 2);
94 *(uniname
+ cchDomain
) = '\\';
95 memcpy (uniname
+ cchDomain
+ 1, user
, cchName
* 2);
99 /* no domain / machine */
105 /* nothing -> return NULL */
116 #else /* not HOST_WIN32 */
118 #define MONO_SYSCONF_DEFAULT_SIZE ((size_t) 1024)
121 * Ensure we always get a valid (usable) value from sysconf.
122 * In case of error, we return the default value.
124 static size_t mono_sysconf (int name
)
126 size_t size
= (size_t) sysconf (name
);
128 return (size
== -1) ? MONO_SYSCONF_DEFAULT_SIZE
: size
;
133 GetTokenName (uid_t uid
)
137 #ifdef HAVE_GETPWUID_R
143 struct passwd
*p
= NULL
;
146 #ifdef HAVE_GETPWUID_R
147 #ifdef _SC_GETPW_R_SIZE_MAX
148 fbufsize
= mono_sysconf (_SC_GETPW_R_SIZE_MAX
);
150 fbufsize
= MONO_SYSCONF_DEFAULT_SIZE
;
152 fbuf
= g_malloc0 (fbufsize
);
153 retval
= getpwuid_r (uid
, &pwd
, fbuf
, fbufsize
, &p
);
154 result
= ((retval
== 0) && (p
== &pwd
));
156 /* default to non thread-safe but posix compliant function */
158 result
= (p
!= NULL
);
162 uname
= g_strdup (p
->pw_name
);
165 #ifdef HAVE_GETPWUID_R
174 IsMemberInList (uid_t user
, struct group
*g
)
176 gboolean result
= FALSE
;
177 gchar
*utf8_username
= GetTokenName (user
);
183 gchar
**users
= g
->gr_mem
;
187 if (strcmp (utf8_username
, u
) == 0) {
195 g_free (utf8_username
);
201 IsDefaultGroup (uid_t user
, gid_t group
)
203 #ifdef HAVE_GETPWUID_R
209 struct passwd
*p
= NULL
;
212 #ifdef HAVE_GETPWUID_R
213 #ifdef _SC_GETPW_R_SIZE_MAX
214 fbufsize
= mono_sysconf (_SC_GETPW_R_SIZE_MAX
);
216 fbufsize
= MONO_SYSCONF_DEFAULT_SIZE
;
219 fbuf
= g_malloc0 (fbufsize
);
220 retval
= getpwuid_r (user
, &pwd
, fbuf
, fbufsize
, &p
);
221 result
= ((retval
== 0) && (p
== &pwd
));
223 /* default to non thread-safe but posix compliant function */
225 result
= (p
!= NULL
);
229 result
= (p
->pw_gid
== group
);
232 #ifdef HAVE_GETPWUID_R
241 IsMemberOf (gid_t user
, struct group
*g
)
246 /* is it the user default group */
247 if (IsDefaultGroup (user
, g
->gr_gid
))
250 /* is the user in the group list */
251 return IsMemberInList (user
, g
);
260 /* System.Security.Principal.WindowsIdentity */
264 ves_icall_System_Security_Principal_WindowsIdentity_GetCurrentToken (void)
266 gpointer token
= NULL
;
271 /* Note: This isn't a copy of the Token - we must not close it!!!
272 * http://www.develop.com/kbrown/book/html/whatis_windowsprincipal.html
275 /* thread may be impersonating somebody */
276 if (OpenThreadToken (GetCurrentThread (), TOKEN_QUERY
, 1, &token
) == 0) {
277 /* if not take the process identity */
278 OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY
, &token
);
281 token
= GINT_TO_POINTER (geteuid ());
288 ves_icall_System_Security_Principal_WindowsIdentity_GetTokenName (gpointer token
)
290 MonoString
*result
= NULL
;
291 gunichar2
*uniname
= NULL
;
297 GetTokenInformation (token
, TokenUser
, NULL
, size
, (PDWORD
)&size
);
299 TOKEN_USER
*tu
= g_malloc0 (size
);
300 if (GetTokenInformation (token
, TokenUser
, tu
, size
, (PDWORD
)&size
)) {
301 uniname
= GetSidName (NULL
, tu
->User
.Sid
, &size
);
306 gchar
*uname
= GetTokenName ((uid_t
) GPOINTER_TO_INT (token
));
311 size
= strlen (uname
);
312 uniname
= g_utf8_to_utf16 (uname
, size
, NULL
, NULL
, NULL
);
315 #endif /* HOST_WIN32 */
318 result
= mono_string_new_utf16 (mono_domain_get (), uniname
, size
);
321 result
= mono_string_new (mono_domain_get (), "");
331 ves_icall_System_Security_Principal_WindowsIdentity_GetUserToken (MonoString
*username
)
334 gpointer token
= NULL
;
338 /* TODO: MS has something like this working in Windows 2003 (client and
339 * server) but works only for domain accounts (so it's quite limiting).
340 * http://www.develop.com/kbrown/book/html/howto_logonuser.html
342 g_warning ("Unsupported on Win32 (anyway requires W2K3 minimum)");
344 #else /* HOST_WIN32*/
346 #ifdef HAVE_GETPWNAM_R
352 gpointer token
= (gpointer
) -2;
359 utf8_name
= mono_unicode_to_external (mono_string_chars (username
));
361 #ifdef HAVE_GETPWNAM_R
362 #ifdef _SC_GETPW_R_SIZE_MAX
363 fbufsize
= mono_sysconf (_SC_GETPW_R_SIZE_MAX
);
365 fbufsize
= MONO_SYSCONF_DEFAULT_SIZE
;
368 fbuf
= g_malloc0 (fbufsize
);
369 retval
= getpwnam_r (utf8_name
, &pwd
, fbuf
, fbufsize
, &p
);
370 result
= ((retval
== 0) && (p
== &pwd
));
372 /* default to non thread-safe but posix compliant function */
373 p
= getpwnam (utf8_name
);
374 result
= (p
!= NULL
);
378 token
= GINT_TO_POINTER (p
->pw_uid
);
381 #ifdef HAVE_GETPWNAM_R
390 /* http://www.dotnet247.com/247reference/msgs/39/195403.aspx
391 // internal static string[] WindowsIdentity._GetRoles (IntPtr token)
394 ves_icall_System_Security_Principal_WindowsIdentity_GetRoles (gpointer token
)
396 MonoArray
*array
= NULL
;
397 MonoDomain
*domain
= mono_domain_get ();
403 GetTokenInformation (token
, TokenGroups
, NULL
, size
, (PDWORD
)&size
);
405 TOKEN_GROUPS
*tg
= g_malloc0 (size
);
406 if (GetTokenInformation (token
, TokenGroups
, tg
, size
, (PDWORD
)&size
)) {
408 int num
= tg
->GroupCount
;
410 array
= mono_array_new (domain
, mono_get_string_class (), num
);
412 for (i
=0; i
< num
; i
++) {
414 gunichar2
*uniname
= GetSidName (NULL
, tg
->Groups
[i
].Sid
, &size
);
417 MonoString
*str
= mono_string_new_utf16 (domain
, uniname
, size
);
418 mono_array_setref (array
, i
, str
);
426 /* POSIX-compliant systems should use IsMemberOfGroupId or IsMemberOfGroupName */
427 g_warning ("WindowsIdentity._GetRoles should never be called on POSIX");
430 /* return empty array of string, i.e. string [0] */
431 array
= mono_array_new (domain
, mono_get_string_class (), 0);
437 /* System.Security.Principal.WindowsImpersonationContext */
441 ves_icall_System_Security_Principal_WindowsImpersonationContext_CloseToken (gpointer token
)
443 gboolean result
= TRUE
;
448 result
= (CloseHandle (token
) != 0);
455 ves_icall_System_Security_Principal_WindowsImpersonationContext_DuplicateToken (gpointer token
)
457 gpointer dupe
= NULL
;
462 if (DuplicateToken (token
, SecurityImpersonation
, &dupe
) == 0) {
473 ves_icall_System_Security_Principal_WindowsImpersonationContext_SetCurrentToken (gpointer token
)
477 /* Posix version implemented in /mono/mono/io-layer/security.c */
478 return (ImpersonateLoggedOnUser (token
) != 0);
483 ves_icall_System_Security_Principal_WindowsImpersonationContext_RevertToSelf (void)
487 /* Posix version implemented in /mono/mono/io-layer/security.c */
488 return (RevertToSelf () != 0);
492 /* System.Security.Principal.WindowsPrincipal */
495 ves_icall_System_Security_Principal_WindowsPrincipal_IsMemberOfGroupId (gpointer user
, gpointer group
)
497 gboolean result
= FALSE
;
502 /* The convertion from an ID to a string is done in managed code for Windows */
503 g_warning ("IsMemberOfGroupId should never be called on Win32");
505 #else /* HOST_WIN32 */
507 #ifdef HAVE_GETGRGID_R
513 struct group
*g
= NULL
;
517 #ifdef HAVE_GETGRGID_R
518 #ifdef _SC_GETGR_R_SIZE_MAX
519 fbufsize
= mono_sysconf (_SC_GETGR_R_SIZE_MAX
);
521 fbufsize
= MONO_SYSCONF_DEFAULT_SIZE
;
523 fbuf
= g_malloc0 (fbufsize
);
524 retval
= getgrgid_r ((gid_t
) GPOINTER_TO_INT (group
), &grp
, fbuf
, fbufsize
, &g
);
525 result
= ((retval
== 0) && (g
== &grp
));
527 /* default to non thread-safe but posix compliant function */
528 g
= getgrgid ((gid_t
) GPOINTER_TO_INT (group
));
529 result
= (g
!= NULL
);
533 result
= IsMemberOf ((uid_t
) GPOINTER_TO_INT (user
), g
);
536 #ifdef HAVE_GETGRGID_R
540 #endif /* HOST_WIN32 */
547 ves_icall_System_Security_Principal_WindowsPrincipal_IsMemberOfGroupName (gpointer user
, MonoString
*group
)
549 gboolean result
= FALSE
;
555 /* Windows version use a cache built using WindowsIdentity._GetRoles */
556 g_warning ("IsMemberOfGroupName should never be called on Win32");
558 #else /* HOST_WIN32 */
559 gchar
*utf8_groupname
;
563 utf8_groupname
= mono_unicode_to_external (mono_string_chars (group
));
564 if (utf8_groupname
) {
565 struct group
*g
= NULL
;
566 #ifdef HAVE_GETGRNAM_R
570 #ifdef _SC_GETGR_R_SIZE_MAX
571 size_t fbufsize
= mono_sysconf (_SC_GETGR_R_SIZE_MAX
);
573 size_t fbufsize
= MONO_SYSCONF_DEFAULT_SIZE
;
575 fbuf
= g_malloc0 (fbufsize
);
576 retval
= getgrnam_r (utf8_groupname
, &grp
, fbuf
, fbufsize
, &g
);
577 result
= ((retval
== 0) && (g
== &grp
));
579 /* default to non thread-safe but posix compliant function */
580 g
= getgrnam (utf8_groupname
);
581 result
= (g
!= NULL
);
585 result
= IsMemberOf ((uid_t
) GPOINTER_TO_INT (user
), g
);
588 #ifdef HAVE_GETGRNAM_R
591 g_free (utf8_groupname
);
593 #endif /* HOST_WIN32 */
599 /* Mono.Security.Cryptography IO related internal calls */
604 GetAdministratorsSid (void)
606 SID_IDENTIFIER_AUTHORITY admins
= SECURITY_NT_AUTHORITY
;
608 if (!AllocateAndInitializeSid (&admins
, 2, SECURITY_BUILTIN_DOMAIN_RID
,
609 DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0, &pSid
))
611 /* Note: this SID must be freed with FreeSid () */
617 GetEveryoneSid (void)
619 SID_IDENTIFIER_AUTHORITY everyone
= SECURITY_WORLD_SID_AUTHORITY
;
621 if (!AllocateAndInitializeSid (&everyone
, 1, SECURITY_WORLD_RID
, 0, 0, 0, 0, 0, 0, 0, &pSid
))
623 /* Note: this SID must be freed with FreeSid () */
629 GetCurrentUserSid (void)
633 gpointer token
= ves_icall_System_Security_Principal_WindowsIdentity_GetCurrentToken ();
635 GetTokenInformation (token
, TokenUser
, NULL
, size
, (PDWORD
)&size
);
637 TOKEN_USER
*tu
= g_malloc0 (size
);
638 if (GetTokenInformation (token
, TokenUser
, tu
, size
, (PDWORD
)&size
)) {
639 DWORD length
= GetLengthSid (tu
->User
.Sid
);
640 sid
= (PSID
) g_malloc0 (length
);
641 if (!CopySid (length
, sid
, tu
->User
.Sid
)) {
648 /* Note: this SID must be freed with g_free () */
654 GetRightsFromSid (PSID sid
, PACL acl
)
656 ACCESS_MASK rights
= 0;
659 BuildTrusteeWithSidW (&trustee
, sid
);
660 if (GetEffectiveRightsFromAcl (acl
, &trustee
, &rights
) != ERROR_SUCCESS
)
668 IsMachineProtected (gunichar2
*path
)
670 gboolean success
= FALSE
;
672 PSID pEveryoneSid
= NULL
;
674 DWORD dwRes
= GetNamedSecurityInfoW (path
, SE_FILE_OBJECT
, DACL_SECURITY_INFORMATION
, NULL
, NULL
, &pDACL
, NULL
, NULL
);
675 if (dwRes
!= ERROR_SUCCESS
)
678 /* We check that Everyone is still limited to READ-ONLY -
679 but not if new entries have been added by an Administrator */
681 pEveryoneSid
= GetEveryoneSid ();
683 ACCESS_MASK rights
= GetRightsFromSid (pEveryoneSid
, pDACL
);
684 /* http://msdn.microsoft.com/library/en-us/security/security/generic_access_rights.asp?frame=true */
685 success
= (rights
== (READ_CONTROL
| SYNCHRONIZE
| FILE_READ_DATA
| FILE_READ_EA
| FILE_READ_ATTRIBUTES
));
686 FreeSid (pEveryoneSid
);
688 /* Note: we don't need to check our own access -
689 we'll know soon enough when reading the file */
699 IsUserProtected (gunichar2
*path
)
701 gboolean success
= FALSE
;
703 PSID pEveryoneSid
= NULL
;
705 DWORD dwRes
= GetNamedSecurityInfoW (path
, SE_FILE_OBJECT
,
706 DACL_SECURITY_INFORMATION
, NULL
, NULL
, &pDACL
, NULL
, NULL
);
707 if (dwRes
!= ERROR_SUCCESS
)
710 /* We check that our original entries in the ACL are in place -
711 but not if new entries have been added by the user */
713 /* Everyone should be denied */
714 pEveryoneSid
= GetEveryoneSid ();
716 ACCESS_MASK rights
= GetRightsFromSid (pEveryoneSid
, pDACL
);
717 success
= (rights
== 0);
718 FreeSid (pEveryoneSid
);
720 /* Note: we don't need to check our own access -
721 we'll know soon enough when reading the file */
731 ProtectMachine (gunichar2
*path
)
733 PSID pEveryoneSid
= GetEveryoneSid ();
734 PSID pAdminsSid
= GetAdministratorsSid ();
737 if (pEveryoneSid
&& pAdminsSid
) {
739 EXPLICIT_ACCESS ea
[2];
740 ZeroMemory (&ea
, 2 * sizeof (EXPLICIT_ACCESS
));
742 /* grant all access to the BUILTIN\Administrators group */
743 BuildTrusteeWithSidW (&ea
[0].Trustee
, pAdminsSid
);
744 ea
[0].grfAccessPermissions
= GENERIC_ALL
;
745 ea
[0].grfAccessMode
= SET_ACCESS
;
746 ea
[0].grfInheritance
= SUB_CONTAINERS_AND_OBJECTS_INHERIT
;
747 ea
[0].Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
748 ea
[0].Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
750 /* read-only access everyone */
751 BuildTrusteeWithSidW (&ea
[1].Trustee
, pEveryoneSid
);
752 ea
[1].grfAccessPermissions
= GENERIC_READ
;
753 ea
[1].grfAccessMode
= SET_ACCESS
;
754 ea
[1].grfInheritance
= SUB_CONTAINERS_AND_OBJECTS_INHERIT
;
755 ea
[1].Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
756 ea
[1].Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
758 retval
= SetEntriesInAcl (2, ea
, NULL
, &pDACL
);
759 if (retval
== ERROR_SUCCESS
) {
760 /* with PROTECTED_DACL_SECURITY_INFORMATION we */
761 /* remove any existing ACL (like inherited ones) */
762 retval
= SetNamedSecurityInfo (path
, SE_FILE_OBJECT
,
763 DACL_SECURITY_INFORMATION
| PROTECTED_DACL_SECURITY_INFORMATION
,
764 NULL
, NULL
, pDACL
, NULL
);
771 FreeSid (pEveryoneSid
);
773 FreeSid (pAdminsSid
);
774 return (retval
== ERROR_SUCCESS
);
779 ProtectUser (gunichar2
*path
)
783 PSID pCurrentSid
= GetCurrentUserSid ();
787 ZeroMemory (&ea
, sizeof (EXPLICIT_ACCESS
));
789 /* grant exclusive access to the current user */
790 BuildTrusteeWithSidW (&ea
.Trustee
, pCurrentSid
);
791 ea
.grfAccessPermissions
= GENERIC_ALL
;
792 ea
.grfAccessMode
= SET_ACCESS
;
793 ea
.grfInheritance
= SUB_CONTAINERS_AND_OBJECTS_INHERIT
;
794 ea
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
795 ea
.Trustee
.TrusteeType
= TRUSTEE_IS_USER
;
797 retval
= SetEntriesInAcl (1, &ea
, NULL
, &pDACL
);
798 if (retval
== ERROR_SUCCESS
) {
799 /* with PROTECTED_DACL_SECURITY_INFORMATION we
800 remove any existing ACL (like inherited ones) */
801 retval
= SetNamedSecurityInfo (path
, SE_FILE_OBJECT
,
802 DACL_SECURITY_INFORMATION
| PROTECTED_DACL_SECURITY_INFORMATION
,
803 NULL
, NULL
, pDACL
, NULL
);
808 g_free (pCurrentSid
); /* g_malloc0 */
811 return (retval
== ERROR_SUCCESS
);
817 IsProtected (MonoString
*path
, gint32 protection
)
819 gboolean result
= FALSE
;
820 gchar
*utf8_name
= mono_unicode_to_external (mono_string_chars (path
));
823 if (stat (utf8_name
, &st
) == 0) {
824 result
= (((st
.st_mode
& 0777) & protection
) == 0);
833 Protect (MonoString
*path
, gint32 file_mode
, gint32 add_dir_mode
)
835 gboolean result
= FALSE
;
836 gchar
*utf8_name
= mono_unicode_to_external (mono_string_chars (path
));
839 if (stat (utf8_name
, &st
) == 0) {
840 int mode
= file_mode
;
841 if (st
.st_mode
& S_IFDIR
)
842 mode
|= add_dir_mode
;
843 result
= (chmod (utf8_name
, mode
) == 0);
850 #endif /* not HOST_WIN32 */
854 ves_icall_Mono_Security_Cryptography_KeyPairPersistence_CanSecure (MonoString
*root
)
861 /* ACL are nice... unless you have FAT or other uncivilized filesystem */
862 if (!GetVolumeInformation (mono_string_chars (root
), NULL
, 0, NULL
, NULL
, (LPDWORD
)&flags
, NULL
, 0))
864 return ((flags
& FS_PERSISTENT_ACLS
) == FS_PERSISTENT_ACLS
);
867 /* we assume some kind of security is applicable outside Windows */
874 ves_icall_Mono_Security_Cryptography_KeyPairPersistence_IsMachineProtected (MonoString
*path
)
876 gboolean ret
= FALSE
;
880 /* no one, but the owner, should have write access to the directory */
882 ret
= IsMachineProtected (mono_string_chars (path
));
884 ret
= IsProtected (path
, (S_IWGRP
| S_IWOTH
));
891 ves_icall_Mono_Security_Cryptography_KeyPairPersistence_IsUserProtected (MonoString
*path
)
893 gboolean ret
= FALSE
;
897 /* no one, but the user, should have access to the directory */
899 ret
= IsUserProtected (mono_string_chars (path
));
901 ret
= IsProtected (path
, (S_IRGRP
| S_IWGRP
| S_IXGRP
| S_IROTH
| S_IWOTH
| S_IXOTH
));
908 ves_icall_Mono_Security_Cryptography_KeyPairPersistence_ProtectMachine (MonoString
*path
)
910 gboolean ret
= FALSE
;
914 /* read/write to owner, read to everyone else */
916 ret
= ProtectMachine (mono_string_chars (path
));
918 ret
= Protect (path
, (S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
), (S_IXUSR
| S_IXGRP
| S_IXOTH
));
925 ves_icall_Mono_Security_Cryptography_KeyPairPersistence_ProtectUser (MonoString
*path
)
927 gboolean ret
= FALSE
;
931 /* read/write to user, no access to everyone else */
933 ret
= ProtectUser (mono_string_chars (path
));
935 ret
= Protect (path
, (S_IRUSR
| S_IWUSR
), S_IXUSR
);
942 * Returns TRUE if there is "something" where the Authenticode signature is
943 * normally located. Returns FALSE is data directory is empty.
945 * Note: Neither the structure nor the signature is verified by this function.
948 ves_icall_System_Security_Policy_Evidence_IsAuthenticodePresent (MonoReflectionAssembly
*refass
)
950 if (refass
&& refass
->assembly
&& refass
->assembly
->image
) {
951 return mono_image_has_authenticode_entry (refass
->assembly
->image
);
957 /* System.Security.SecureString related internal calls */
959 static MonoImage
*system_security_assembly
= NULL
;
962 ves_icall_System_Security_SecureString_DecryptInternal (MonoArray
*data
, MonoObject
*scope
)
964 invoke_protected_memory_method (data
, scope
, FALSE
);
967 ves_icall_System_Security_SecureString_EncryptInternal (MonoArray
* data
, MonoObject
*scope
)
969 invoke_protected_memory_method (data
, scope
, TRUE
);
972 void invoke_protected_memory_method (MonoArray
*data
, MonoObject
*scope
, gboolean encrypt
)
980 if (system_security_assembly
== NULL
) {
981 system_security_assembly
= mono_image_loaded ("System.Security");
982 if (!system_security_assembly
) {
983 MonoAssembly
*sa
= mono_assembly_open ("System.Security.dll", NULL
);
985 g_assert_not_reached ();
986 system_security_assembly
= mono_assembly_get_image (sa
);
990 klass
= mono_class_from_name (system_security_assembly
,
991 "System.Security.Cryptography", "ProtectedMemory");
992 method
= mono_class_get_method_from_name (klass
, encrypt
? "Protect" : "Unprotect", 2);
994 params
[1] = scope
; /* MemoryProtectionScope.SameProcess */
995 mono_runtime_invoke (method
, NULL
, params
, NULL
);