Merge remote-tracking branch 'upstream/master'
[mono.git] / mono / metadata / security-manager.c
1 /*
2  * security-manager.c:  Security Manager (Unmanaged side)
3  *
4  * Author:
5  *      Sebastien Pouliot  <sebastien@ximian.com>
6  *
7  * Copyright 2005-2009 Novell, Inc (http://www.novell.com)
8  */
9
10 #include "security-manager.h"
11
12 static MonoSecurityMode mono_security_mode = MONO_SECURITY_MODE_NONE;
13 static MonoBoolean mono_security_manager_activated = FALSE;
14 static MonoBoolean mono_security_manager_enabled = TRUE;
15 static MonoBoolean mono_security_manager_execution = TRUE;
16
17 void
18 mono_security_set_mode (MonoSecurityMode mode)
19 {
20         mono_security_mode = mode;
21 }
22
23 MonoSecurityMode
24 mono_security_get_mode (void)
25 {
26         return mono_security_mode;
27 }
28
29 /*
30  * Note: The security manager is activate once when executing the Mono. This 
31  * is not meant to be a turn on/off runtime switch.
32  */
33 void
34 mono_activate_security_manager (void)
35 {
36         mono_security_manager_activated = TRUE;
37 }
38
39 gboolean
40 mono_is_security_manager_active (void)
41 {
42         return mono_security_manager_activated;
43 }
44
45 #ifndef DISABLE_SECURITY
46
47 static MonoSecurityManager secman;
48
49 MonoSecurityManager*
50 mono_security_manager_get_methods (void)
51 {
52         /* Already initialized ? */
53         if (secman.securitymanager)
54                 return &secman;
55
56         /* Initialize */
57         secman.securitymanager = mono_class_from_name (mono_defaults.corlib, 
58                 "System.Security", "SecurityManager");
59         g_assert (secman.securitymanager);
60         if (!secman.securitymanager->inited)
61                 mono_class_init (secman.securitymanager);
62                 
63         secman.demand = mono_class_get_method_from_name (secman.securitymanager,
64                 "InternalDemand", 2);   
65         g_assert (secman.demand);
66
67         secman.demandchoice = mono_class_get_method_from_name (secman.securitymanager,
68                 "InternalDemandChoice", 2);     
69         g_assert (secman.demandchoice);
70
71         secman.demandunmanaged = mono_class_get_method_from_name (secman.securitymanager,
72                 "DemandUnmanaged", 0);
73         g_assert (secman.demandunmanaged);
74
75         secman.inheritancedemand = mono_class_get_method_from_name (secman.securitymanager,
76                 "InheritanceDemand", 3);        
77         g_assert (secman.inheritancedemand);
78
79         secman.inheritsecurityexception = mono_class_get_method_from_name (secman.securitymanager,
80                 "InheritanceDemandSecurityException", 4);       
81         g_assert (secman.inheritsecurityexception);
82
83         secman.linkdemand = mono_class_get_method_from_name (secman.securitymanager,
84                 "LinkDemand", 3);
85         g_assert (secman.linkdemand);
86
87         secman.linkdemandunmanaged = mono_class_get_method_from_name (secman.securitymanager,
88                 "LinkDemandUnmanaged", 1);
89         g_assert (secman.linkdemandunmanaged);
90
91         secman.linkdemandfulltrust = mono_class_get_method_from_name (secman.securitymanager,
92                 "LinkDemandFullTrust", 1);
93         g_assert (secman.linkdemandfulltrust);
94
95         secman.linkdemandsecurityexception = mono_class_get_method_from_name (secman.securitymanager,
96                 "LinkDemandSecurityException", 2);
97         g_assert (secman.linkdemandsecurityexception);
98
99         secman.allowpartiallytrustedcallers = mono_class_from_name (mono_defaults.corlib, "System.Security", 
100                 "AllowPartiallyTrustedCallersAttribute");
101         g_assert (secman.allowpartiallytrustedcallers);
102
103         secman.suppressunmanagedcodesecurity = mono_class_from_name (mono_defaults.corlib, "System.Security", 
104                 "SuppressUnmanagedCodeSecurityAttribute");
105         g_assert (secman.suppressunmanagedcodesecurity);
106
107         return &secman;
108 }
109
110 static gboolean
111 mono_secman_inheritance_check (MonoClass *klass, MonoDeclSecurityActions *demands)
112 {
113         MonoSecurityManager* secman = mono_security_manager_get_methods ();
114         MonoDomain *domain = mono_domain_get ();
115         MonoAssembly *assembly = mono_image_get_assembly (klass->image);
116         MonoReflectionAssembly *refass = mono_assembly_get_object (domain, assembly);
117         MonoObject *res;
118         gpointer args [3];
119
120         args [0] = domain->domain;
121         args [1] = refass;
122         args [2] = demands;
123
124         res = mono_runtime_invoke (secman->inheritancedemand, NULL, args, NULL);
125         return (*(MonoBoolean *) mono_object_unbox (res));
126 }
127
128 void
129 mono_secman_inheritancedemand_class (MonoClass *klass, MonoClass *parent)
130 {
131         MonoDeclSecurityActions demands;
132
133         /* don't hide previous results -and- don't calc everything for nothing */
134         if (klass->exception_type != 0)
135                 return;
136
137         /* short-circuit corlib as it is fully trusted (within itself)
138          * and because this cause major recursion headaches */
139         if ((klass->image == mono_defaults.corlib) && (parent->image == mono_defaults.corlib))
140                 return;
141
142         /* Check if there are an InheritanceDemand on the parent class */
143         if (mono_declsec_get_inheritdemands_class (parent, &demands)) {
144                 /* If so check the demands on the klass (inheritor) */
145                 if (!mono_secman_inheritance_check (klass, &demands)) {
146                         /* Keep flags in MonoClass to be able to throw a SecurityException later (if required) */
147                         mono_class_set_failure (klass, MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND, NULL);
148                 }
149         }
150 }
151
152 void
153 mono_secman_inheritancedemand_method (MonoMethod *override, MonoMethod *base)
154 {
155         MonoDeclSecurityActions demands;
156
157         /* don't hide previous results -and- don't calc everything for nothing */
158         if (override->klass->exception_type != 0)
159                 return;
160
161         /* short-circuit corlib as it is fully trusted (within itself)
162          * and because this cause major recursion headaches */
163         if ((override->klass->image == mono_defaults.corlib) && (base->klass->image == mono_defaults.corlib))
164                 return;
165
166         /* Check if there are an InheritanceDemand on the base (virtual) method */
167         if (mono_declsec_get_inheritdemands_method (base, &demands)) {
168                 /* If so check the demands on the overriding method */
169                 if (!mono_secman_inheritance_check (override->klass, &demands)) {
170                         /* Keep flags in MonoClass to be able to throw a SecurityException later (if required) */
171                         mono_class_set_failure (override->klass, MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND, base);
172                 }
173         }
174 }
175
176 #else
177
178 MonoSecurityManager*
179 mono_security_manager_get_methods (void)
180 {
181         return NULL;
182 }
183
184 void
185 mono_secman_inheritancedemand_class (MonoClass *klass, MonoClass *parent)
186 {
187 }
188
189 void
190 mono_secman_inheritancedemand_method (MonoMethod *override, MonoMethod *base)
191 {
192 }
193
194 #endif /* DISABLE_SECURITY */
195
196 /*
197  * @publickey   An encoded (with header) public key
198  * @size        The length of the public key
199  *
200  * returns TRUE if the public key is the ECMA "key", FALSE otherwise
201  *
202  * ECMA key isn't a real public key - it's simply an empty (but valid) header
203  * so it's length (16) and value (00000000000000000400000000000000) are 
204  * constants.
205  */
206 gboolean 
207 mono_is_ecma_key (const char *publickey, int size)
208 {
209         int i;
210         if ((publickey == NULL) || (size != MONO_ECMA_KEY_LENGTH) || (publickey [8] != 0x04))
211                 return FALSE;
212
213         for (i=0; i < size; i++) {
214                 if ((publickey [i] != 0x00) && (i != 8))
215                         return FALSE;
216         }
217         return TRUE;
218 }
219
220 /*
221  * Context propagation is required when:
222  * (a) the security manager is active (1.x and later)
223  * (b) other contexts needs to be propagated (2.x and later)
224  *
225  * returns NULL if no context propagation is required, else the returns the
226  * MonoMethod to call to Capture the ExecutionContext.
227  */
228 MonoMethod*
229 mono_get_context_capture_method (void)
230 {
231         static MonoMethod *method = NULL;
232
233         if (!mono_security_manager_activated) {
234                 if (mono_image_get_assembly (mono_defaults.corlib)->aname.major < 2)
235                         return NULL;
236         }
237
238         /* older corlib revisions won't have the class (nor the method) */
239         if (mono_defaults.executioncontext_class && !method) {
240                 mono_class_init (mono_defaults.executioncontext_class);
241                 method = mono_class_get_method_from_name (mono_defaults.executioncontext_class, "Capture", 0);
242         }
243
244         return method;
245 }
246
247
248 /* System.Security icalls */
249
250 MonoBoolean
251 ves_icall_System_Security_SecurityManager_get_SecurityEnabled (void)
252 {
253         if (!mono_security_manager_activated) {
254                 /* SecurityManager is internal for Moonlight and SecurityEnabled is used to know if CoreCLR is active
255                  * (e.g. plugin executing in the browser) or not (e.g. smcs compiling source code with corlib 2.1)
256                  */
257                 return (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR);
258         }
259         return mono_security_manager_enabled;
260 }
261
262 void
263 ves_icall_System_Security_SecurityManager_set_SecurityEnabled (MonoBoolean value)
264 {
265         /* value can be changed only if the security manager is activated */
266         if (mono_security_manager_activated) {
267                 mono_security_manager_enabled = value;
268         }
269 }
270
271 MonoBoolean
272 ves_icall_System_Security_SecurityManager_get_CheckExecutionRights (void)
273 {
274         if (!mono_security_manager_activated)
275                 return FALSE;
276         return mono_security_manager_execution;
277 }
278
279 void
280 ves_icall_System_Security_SecurityManager_set_CheckExecutionRights (MonoBoolean value)
281 {
282         /* value can be changed only id the security manager is activated */
283         if (mono_security_manager_activated) {
284                 mono_security_manager_execution = value;
285         }
286 }
287
288 MonoBoolean
289 ves_icall_System_Security_SecurityManager_GetLinkDemandSecurity (MonoReflectionMethod *m, MonoDeclSecurityActions *kactions, MonoDeclSecurityActions *mactions)
290 {
291         MonoMethod *method = m->method;
292         /* we want the original as the wrapper is "free" of the security informations */
293         if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
294                 method = mono_marshal_method_from_wrapper (method);
295         }
296
297         mono_class_init (method->klass);
298
299         /* if either the method or it's class has security (any type) */
300         if ((method->flags & METHOD_ATTRIBUTE_HAS_SECURITY) || (method->klass->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) {
301                 memset (kactions, 0, sizeof (MonoDeclSecurityActions));
302                 memset (mactions, 0, sizeof (MonoDeclSecurityActions));
303
304                 /* get any linkdemand (either on the method or it's class) */
305                 return mono_declsec_get_linkdemands (method, kactions, mactions);
306         }
307         return FALSE;
308 }