BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / corlib / System.Security.Principal / WindowsIdentity.cs
1 //
2 // System.Security.Principal.WindowsIdentity
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //      Sebastien Pouliot (sebastien@ximian.com)
7 //
8 // (C) 2002 Ximian, Inc (http://www.ximian.com)
9 // Portions (C) 2003 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Runtime.CompilerServices;
33 using System.Runtime.InteropServices;
34 using System.Runtime.Serialization;
35 using System.Security.Permissions;
36
37 namespace System.Security.Principal {
38
39         [Serializable]
40         [ComVisible (true)]
41         public class WindowsIdentity : IIdentity, IDeserializationCallback, ISerializable, IDisposable {
42                 private IntPtr _token;
43                 private string _type;
44                 private WindowsAccountType _account;
45                 private bool _authenticated;
46                 private string _name;
47                 private SerializationInfo _info;
48
49                 static private IntPtr invalidWindows = IntPtr.Zero;
50
51                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
52                 public WindowsIdentity (IntPtr userToken) 
53                         : this (userToken, null, WindowsAccountType.Normal, false)
54                 {
55                 }
56
57                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
58                 public WindowsIdentity (IntPtr userToken, string type) 
59                         : this (userToken, type, WindowsAccountType.Normal, false)
60                 {
61                 }
62
63                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
64                 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType)
65                         : this (userToken, type, acctType, false)
66                 {
67                 }
68
69                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
70                 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
71                 {
72                         _type = type;
73                         _account = acctType;
74                         _authenticated = isAuthenticated;
75                         _name = null;
76                         // last - as it can override some fields
77                         SetToken (userToken);
78                 }
79 #if !NET_1_0
80                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
81                 public WindowsIdentity (string sUserPrincipalName) 
82                         : this (sUserPrincipalName, null)
83                 {
84                 }
85
86                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
87                 public WindowsIdentity (string sUserPrincipalName, string type)
88                 {
89                         if (sUserPrincipalName == null)
90                                 throw new NullReferenceException ("sUserPrincipalName");
91
92                         // TODO: Windows 2003 compatibility should be done in runtime
93                         IntPtr token = GetUserToken (sUserPrincipalName);
94                         if ((!Environment.IsUnix) && (token == IntPtr.Zero)) {
95                                 throw new ArgumentException ("only for Windows Server 2003 +");
96                         }
97
98                         _authenticated = true;
99                         _account = WindowsAccountType.Normal;
100                         _type = type;
101                         // last - as it can override some fields
102                         SetToken (token);
103                 }
104
105                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
106                 public WindowsIdentity (SerializationInfo info, StreamingContext context)
107                 {
108                         _info = info;
109                 }
110 #endif
111
112                 [ComVisible (false)]
113                 public void Dispose ()
114                 {
115                         _token = IntPtr.Zero;
116                 }
117                 
118                 [ComVisible (false)]
119                 protected virtual void Dispose (bool disposing)
120                 {
121                         _token = IntPtr.Zero;
122                 }
123                 // static methods
124
125                 public static WindowsIdentity GetAnonymous ()
126                 {
127                         WindowsIdentity id = null;
128                         if (Environment.IsUnix) {
129                                 id = new WindowsIdentity ("nobody");
130                                 // special case
131                                 id._account = WindowsAccountType.Anonymous;
132                                 id._authenticated = false;
133                                 id._type = String.Empty;
134                         }
135                         else {
136                                 id = new WindowsIdentity (IntPtr.Zero, String.Empty, WindowsAccountType.Anonymous, false);
137                                 // special case (don't try to resolve the name)
138                                 id._name = String.Empty;
139                         }
140                         return id;
141                 }
142
143                 public static WindowsIdentity GetCurrent ()
144                 {
145                         return new WindowsIdentity (GetCurrentToken (), null, WindowsAccountType.Normal, true);
146                 }
147                 [MonoTODO ("need icall changes")]
148                 public static WindowsIdentity GetCurrent (bool ifImpersonating)
149                 {
150                         throw new NotImplementedException ();
151                 }
152
153                 [MonoTODO ("need icall changes")]
154                 public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess)
155                 {
156                         throw new NotImplementedException ();
157                 }
158                 // methods
159
160                 public virtual WindowsImpersonationContext Impersonate ()
161                 {
162                         return new WindowsImpersonationContext (_token);
163                 }
164
165                 [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
166                 public static WindowsImpersonationContext Impersonate (IntPtr userToken)
167                 {
168                         return new WindowsImpersonationContext (userToken);
169                 }
170
171                 // properties
172
173                 public string AuthenticationType {
174                         get { return _type; }
175                 }
176
177                 public virtual bool IsAnonymous
178                 {
179                         get { return (_account == WindowsAccountType.Anonymous); }
180                 }
181
182                 public virtual bool IsAuthenticated
183                 {
184                         get { return _authenticated; }
185                 }
186
187                 public virtual bool IsGuest
188                 {
189                         get { return (_account == WindowsAccountType.Guest); }
190                 }
191
192                 public virtual bool IsSystem
193                 {
194                         get { return (_account == WindowsAccountType.System); }
195                 }
196
197                 public virtual string Name
198                 {
199                         get {
200                                 if (_name == null) {
201                                         // revolve name (runtime)
202                                         _name = GetTokenName (_token);
203                                 }
204                                 return _name; 
205                         }
206                 }
207
208                 public virtual IntPtr Token
209                 {
210                         get { return _token; }
211                 }
212                 [MonoTODO ("not implemented")]
213                 public IdentityReferenceCollection Groups {
214                         get { throw new NotImplementedException (); }
215                 }
216
217                 [MonoTODO ("not implemented")]
218                 [ComVisible (false)]
219                 public TokenImpersonationLevel ImpersonationLevel {
220                         get { throw new NotImplementedException (); }
221                 }
222
223                 [MonoTODO ("not implemented")]
224                 [ComVisible (false)]
225                 public SecurityIdentifier Owner {
226                         get { throw new NotImplementedException (); }
227                 }
228
229                 [MonoTODO ("not implemented")]
230                 [ComVisible (false)]
231                 public SecurityIdentifier User {
232                         get { throw new NotImplementedException (); }
233                 }
234                 void IDeserializationCallback.OnDeserialization (object sender)
235                 {
236                         _token = (IntPtr) _info.GetValue ("m_userToken", typeof (IntPtr));
237                         // can't trust this alone - we must validate the token
238                         _name = _info.GetString ("m_name");
239                         if (_name != null) {
240                                 // validate token by comparing names
241                                 string name = GetTokenName (_token);
242                                 if (name != _name)
243                                         throw new SerializationException ("Token-Name mismatch.");
244                         }
245                         else {
246                                 // validate token by getting name
247                                 _name = GetTokenName (_token);
248                                 if ((_name == String.Empty) || (_name == null))
249                                         throw new SerializationException ("Token doesn't match a user.");
250                         }
251                         _type = _info.GetString ("m_type");
252                         _account = (WindowsAccountType) _info.GetValue ("m_acctType", typeof (WindowsAccountType));
253                         _authenticated = _info.GetBoolean ("m_isAuthenticated");
254                 }
255 #if !NET_1_0
256                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) 
257                 {
258                         info.AddValue ("m_userToken", _token);
259                         // can be null when not resolved
260                         info.AddValue ("m_name", _name);
261                         info.AddValue ("m_type", _type);
262                         info.AddValue ("m_acctType", _account);
263                         info.AddValue ("m_isAuthenticated", _authenticated);
264                 }
265 #endif
266                 private void SetToken (IntPtr token) 
267                 {
268                         if (Environment.IsUnix) {
269
270                                 _token = token;
271                                 // apply defaults
272                                 if (_type == null)
273                                         _type = "POSIX";
274                                 // override user choice in this specific case
275                                 if (_token == IntPtr.Zero)
276                                         _account = WindowsAccountType.System;
277                         }
278                         else {
279                                 if ((token == invalidWindows) && (_account != WindowsAccountType.Anonymous))
280                                         throw new ArgumentException ("Invalid token");
281
282                                 _token = token;
283                                 // apply defaults
284                                 if (_type == null)
285                                         _type = "NTLM";
286                         }
287                 }
288
289                 // see mono/mono/metadata/security.c for implementation
290
291                 // Many people use reflection to get a user's roles - so many 
292                 // that's it's hard to say it's an "undocumented" feature -
293                 // so we also implement it in Mono :-/
294                 // http://www.dotnet247.com/247reference/msgs/39/195403.aspx
295                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
296                 internal extern static string[] _GetRoles (IntPtr token);
297
298                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
299                 internal extern static IntPtr GetCurrentToken ();
300
301                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
302                 private extern static string GetTokenName (IntPtr token);
303
304                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
305                 private extern static IntPtr GetUserToken (string username);
306         }
307 }