2004-04-14 Sebastien Pouliot <sebastien@ximian.com>
[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 // (C) 2004 Novell (http://www.novell.com)
11 //
12
13 using System;
14 using System.Runtime.CompilerServices;
15 using System.Runtime.Serialization;
16
17 namespace System.Security.Principal {
18
19         [Serializable]
20 #if NET_1_0
21         public class WindowsIdentity : IIdentity, IDeserializationCallback {
22 #else
23         public class WindowsIdentity : IIdentity, IDeserializationCallback, ISerializable {
24 #endif
25                 private IntPtr _token;
26                 private string _type;
27                 private WindowsAccountType _account;
28                 private bool _authenticated;
29                 private string _name;
30                 private SerializationInfo _info;
31
32                 static private IntPtr invalidWindows = IntPtr.Zero;
33                 // that seems to be the value used for (at least) AIX and MacOSX
34                 static private IntPtr invalidPosix = (IntPtr) unchecked (-2);
35
36                 public WindowsIdentity (IntPtr userToken) 
37                         : this (userToken, null, WindowsAccountType.Normal, false)
38                 {
39                 }
40
41                 public WindowsIdentity (IntPtr userToken, string type) 
42                         : this (userToken, type, WindowsAccountType.Normal, false)
43                 {
44                 }
45
46                 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType)
47                         : this (userToken, type, acctType, false)
48                 {
49                 }
50
51                 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
52                 {
53                         _type = type;
54                         _account = acctType;
55                         _authenticated = isAuthenticated;
56                         _name = null;
57                         // last - as it can override some fields
58                         SetToken (userToken);
59                 }
60 #if !NET_1_0
61                 public WindowsIdentity (string sUserPrincipalName) 
62                         : this (sUserPrincipalName, null)
63                 {
64                 }
65
66                 public WindowsIdentity (string sUserPrincipalName, string type)
67                 {
68                         if (sUserPrincipalName == null)
69                                 throw new NullReferenceException ("sUserPrincipalName");
70
71                         // TODO: Windows 2003 compatibility should be done in runtime
72                         IntPtr token = GetUserToken (sUserPrincipalName);
73                         if ((!IsPosix) && (token == IntPtr.Zero)) {
74                                 throw new ArgumentException ("only for Windows Server 2003 +");
75                         }
76
77                         _authenticated = true;
78                         _account = WindowsAccountType.Normal;
79                         _type = type;
80                         // last - as it can override some fields
81                         SetToken (token);
82                 }
83
84                 public WindowsIdentity (SerializationInfo info, StreamingContext context)
85                 {
86                         _info = info;
87                 }
88 #endif
89
90                 ~WindowsIdentity ()
91                 {
92                         // clear our copy but don't close it
93                         // http://www.develop.com/kbrown/book/html/whatis_windowsprincipal.html
94                         _token = IntPtr.Zero;
95                 }
96
97                 // static methods
98
99                 public static WindowsIdentity GetAnonymous ()
100                 {
101                         WindowsIdentity id = null;
102                         if (IsPosix) {
103                                 id = new WindowsIdentity ("nobody");
104                                 // special case
105                                 id._account = WindowsAccountType.Anonymous;
106                                 id._authenticated = false;
107                                 id._type = String.Empty;
108                         }
109                         else {
110                                 id = new WindowsIdentity (IntPtr.Zero, String.Empty, WindowsAccountType.Anonymous, false);
111                                 // special case (don't try to resolve the name)
112                                 id._name = String.Empty;
113                         }
114                         return id;
115                 }
116
117                 public static WindowsIdentity GetCurrent ()
118                 {
119                         return new WindowsIdentity (GetCurrentToken (), null, WindowsAccountType.Normal, true);
120                 }
121
122                 // methods
123
124                 public virtual WindowsImpersonationContext Impersonate ()
125                 {
126                         return new WindowsImpersonationContext (_token);
127                 }
128
129                 public static WindowsImpersonationContext Impersonate (IntPtr userToken)
130                 {
131                         return new WindowsImpersonationContext (userToken);
132                 }
133
134                 // properties
135
136                 public virtual string AuthenticationType
137                 {
138                         get { return _type; }
139                 }
140
141                 public virtual bool IsAnonymous
142                 {
143                         get { return (_account == WindowsAccountType.Anonymous); }
144                 }
145
146                 public virtual bool IsAuthenticated
147                 {
148                         get { return _authenticated; }
149                 }
150
151                 public virtual bool IsGuest
152                 {
153                         get { return (_account == WindowsAccountType.Guest); }
154                 }
155
156                 public virtual bool IsSystem
157                 {
158                         get { return (_account == WindowsAccountType.System); }
159                 }
160
161                 public virtual string Name
162                 {
163                         get {
164                                 if (_name == null) {
165                                         // revolve name (runtime)
166                                         _name = GetTokenName (_token);
167                                 }
168                                 return _name; 
169                         }
170                 }
171
172                 public virtual IntPtr Token
173                 {
174                         get { return _token; }
175                 }
176
177                 void IDeserializationCallback.OnDeserialization (object sender)
178                 {
179                         _token = (IntPtr) _info.GetValue ("m_userToken", typeof (IntPtr));
180                         // can't trust this alone - we must validate the token
181                         _name = _info.GetString ("m_name");
182                         if (_name != null) {
183                                 // validate token by comparing names
184                                 string name = GetTokenName (_token);
185                                 if (name != _name)
186                                         throw new SerializationException ("Token-Name mismatch.");
187                         }
188                         else {
189                                 // validate token by getting name
190                                 _name = GetTokenName (_token);
191                                 if ((_name == String.Empty) || (_name == null))
192                                         throw new SerializationException ("Token doesn't match a user.");
193                         }
194                         _type = _info.GetString ("m_type");
195                         _account = (WindowsAccountType) _info.GetValue ("m_acctType", typeof (WindowsAccountType));
196                         _authenticated = _info.GetBoolean ("m_isAuthenticated");
197                 }
198 #if !NET_1_0
199                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) 
200                 {
201                         info.AddValue ("m_userToken", _token);
202                         // can be null when not resolved
203                         info.AddValue ("m_name", _name);
204                         info.AddValue ("m_type", _type);
205                         info.AddValue ("m_acctType", _account);
206                         info.AddValue ("m_isAuthenticated", _authenticated);
207                 }
208 #endif
209                 private static bool IsPosix {
210                         get { return ((int) Environment.Platform == 128); }
211                 }
212
213                 private void SetToken (IntPtr token) 
214                 {
215                         if (IsPosix) {
216                                 if (token == invalidPosix)
217                                         throw new ArgumentException ("Invalid token");
218
219                                 _token = token;
220                                 // apply defaults
221                                 if (_type == null)
222                                         _type = "POSIX";
223                                 // override user choice in this specific case
224                                 if (_token == IntPtr.Zero)
225                                         _account = WindowsAccountType.System;
226                         }
227                         else {
228                                 if ((token == invalidWindows) && (_account != WindowsAccountType.Anonymous))
229                                         throw new ArgumentException ("Invalid token");
230
231                                 _token = token;
232                                 // apply defaults
233                                 if (_type == null)
234                                         _type = "NTLM";
235                         }
236                 }
237
238                 // see mono/mono/metadata/security.c for implementation
239
240                 // Many people use reflection to get a user's roles - so many 
241                 // that's it's hard to say it's an "undocumented" feature -
242                 // so we also implement it in Mono :-/
243                 // http://www.dotnet247.com/247reference/msgs/39/195403.aspx
244                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
245                 internal extern static string[] _GetRoles (IntPtr token);
246
247                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
248                 internal extern static IntPtr GetCurrentToken ();
249
250                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
251                 private extern static string GetTokenName (IntPtr token);
252
253                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
254                 private extern static IntPtr GetUserToken (string username);
255         }
256 }