//
// Authors:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
-// Sebastien Pouliot (spouliot@motus.com)
+// Sebastien Pouliot (sebastien@ximian.com)
//
// (C) 2002 Ximian, Inc (http://www.ximian.com)
// Portions (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Runtime.Serialization;
+using System.Security.Permissions;
namespace System.Security.Principal {
[Serializable]
#if NET_1_0
public class WindowsIdentity : IIdentity, IDeserializationCallback {
+#elif NET_2_0
+ [ComVisible (true)]
+ public class WindowsIdentity : IIdentity, IDeserializationCallback, ISerializable, IDisposable {
#else
public class WindowsIdentity : IIdentity, IDeserializationCallback, ISerializable {
#endif
private string _type;
private WindowsAccountType _account;
private bool _authenticated;
+ private string _name;
+ private SerializationInfo _info;
+
+ static private IntPtr invalidWindows = IntPtr.Zero;
+ // that seems to be the value used for (at least) AIX and MacOSX
+ static private IntPtr invalidPosix = (IntPtr) unchecked (-2);
- public WindowsIdentity (IntPtr userToken)
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
+ public WindowsIdentity (IntPtr userToken)
+ : this (userToken, null, WindowsAccountType.Normal, false)
{
- _token = userToken;
- _type = "NTLM";
- _account = WindowsAccountType.Normal;
- _authenticated = false;
}
- public WindowsIdentity (IntPtr userToken, string type)
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
+ public WindowsIdentity (IntPtr userToken, string type)
+ : this (userToken, type, WindowsAccountType.Normal, false)
{
- _token = userToken;
- _type = type;
- _account = WindowsAccountType.Normal;
- _authenticated = false;
}
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType)
+ : this (userToken, type, acctType, false)
{
- _token = userToken;
- _type = type;
- _account = acctType;
- _authenticated = false;
}
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
{
- _token = userToken;
_type = type;
_account = acctType;
_authenticated = isAuthenticated;
+ _name = null;
+ // last - as it can override some fields
+ SetToken (userToken);
}
#if !NET_1_0
- [MonoTODO]
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
public WindowsIdentity (string sUserPrincipalName)
+ : this (sUserPrincipalName, null)
{
- throw new ArgumentException ("only for Windows Server 2003 +");
}
- [MonoTODO]
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
public WindowsIdentity (string sUserPrincipalName, string type)
{
- throw new ArgumentException ("only for Windows Server 2003 +");
+ if (sUserPrincipalName == null)
+ throw new NullReferenceException ("sUserPrincipalName");
+
+ // TODO: Windows 2003 compatibility should be done in runtime
+ IntPtr token = GetUserToken (sUserPrincipalName);
+ if ((!IsPosix) && (token == IntPtr.Zero)) {
+ throw new ArgumentException ("only for Windows Server 2003 +");
+ }
+
+ _authenticated = true;
+ _account = WindowsAccountType.Normal;
+ _type = type;
+ // last - as it can override some fields
+ SetToken (token);
}
- [MonoTODO]
- public WindowsIdentity (SerializationInfo info, StreamingContext context) {}
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
+ public WindowsIdentity (SerializationInfo info, StreamingContext context)
+ {
+ _info = info;
+ }
#endif
- [MonoTODO]
+
+#if NET_2_0
+ [ComVisible (false)]
+ public void Dispose ()
+ {
+ _token = IntPtr.Zero;
+ }
+
+ [ComVisible (false)]
+ protected virtual void Dispose (bool disposing)
+ {
+ _token = IntPtr.Zero;
+ }
+#else
~WindowsIdentity ()
{
- _token = (IntPtr) 0;
+ // clear our copy but don't close it
+ // http://www.develop.com/kbrown/book/html/whatis_windowsprincipal.html
+ _token = IntPtr.Zero;
}
+#endif
+ // static methods
- // methods
-
- [MonoTODO]
public static WindowsIdentity GetAnonymous ()
{
- throw new NotImplementedException ();
+ WindowsIdentity id = null;
+ if (IsPosix) {
+ id = new WindowsIdentity ("nobody");
+ // special case
+ id._account = WindowsAccountType.Anonymous;
+ id._authenticated = false;
+ id._type = String.Empty;
+ }
+ else {
+ id = new WindowsIdentity (IntPtr.Zero, String.Empty, WindowsAccountType.Anonymous, false);
+ // special case (don't try to resolve the name)
+ id._name = String.Empty;
+ }
+ return id;
}
- [MonoTODO]
public static WindowsIdentity GetCurrent ()
+ {
+ return new WindowsIdentity (GetCurrentToken (), null, WindowsAccountType.Normal, true);
+ }
+#if NET_2_0
+ [MonoTODO ("need icall changes")]
+ public static WindowsIdentity GetCurrent (bool ifImpersonating)
{
throw new NotImplementedException ();
}
+ [MonoTODO ("need icall changes")]
+ public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess)
+ {
+ throw new NotImplementedException ();
+ }
+#endif
+ // methods
+
public virtual WindowsImpersonationContext Impersonate ()
{
return new WindowsImpersonationContext (_token);
}
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal=true)]
public static WindowsImpersonationContext Impersonate (IntPtr userToken)
{
return new WindowsImpersonationContext (userToken);
get { return (_account == WindowsAccountType.System); }
}
- [MonoTODO]
public virtual string Name
{
get {
- throw new NotImplementedException ();
+ if (_name == null) {
+ // revolve name (runtime)
+ _name = GetTokenName (_token);
+ }
+ return _name;
}
}
{
get { return _token; }
}
+#if NET_2_0
+ [MonoTODO ("not implemented")]
+ public IdentityReferenceCollection Groups {
+ get { throw new NotImplementedException (); }
+ }
+
+ [MonoTODO ("not implemented")]
+ [ComVisible (false)]
+ public TokenImpersonationLevel ImpersonationLevel {
+ get { throw new NotImplementedException (); }
+ }
- [MonoTODO]
+ [MonoTODO ("not implemented")]
+ [ComVisible (false)]
+ public SecurityIdentifier Owner {
+ get { throw new NotImplementedException (); }
+ }
+
+ [MonoTODO ("not implemented")]
+ [ComVisible (false)]
+ public SecurityIdentifier User {
+ get { throw new NotImplementedException (); }
+ }
+#endif
void IDeserializationCallback.OnDeserialization (object sender)
{
- throw new NotImplementedException ();
+ _token = (IntPtr) _info.GetValue ("m_userToken", typeof (IntPtr));
+ // can't trust this alone - we must validate the token
+ _name = _info.GetString ("m_name");
+ if (_name != null) {
+ // validate token by comparing names
+ string name = GetTokenName (_token);
+ if (name != _name)
+ throw new SerializationException ("Token-Name mismatch.");
+ }
+ else {
+ // validate token by getting name
+ _name = GetTokenName (_token);
+ if ((_name == String.Empty) || (_name == null))
+ throw new SerializationException ("Token doesn't match a user.");
+ }
+ _type = _info.GetString ("m_type");
+ _account = (WindowsAccountType) _info.GetValue ("m_acctType", typeof (WindowsAccountType));
+ _authenticated = _info.GetBoolean ("m_isAuthenticated");
}
#if !NET_1_0
- [MonoTODO]
void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
{
- throw new NotImplementedException ();
+ info.AddValue ("m_userToken", _token);
+ // can be null when not resolved
+ info.AddValue ("m_name", _name);
+ info.AddValue ("m_type", _type);
+ info.AddValue ("m_acctType", _account);
+ info.AddValue ("m_isAuthenticated", _authenticated);
}
#endif
+ private static bool IsPosix {
+ get { return ((int) Environment.Platform == 128); }
+ }
+
+ private void SetToken (IntPtr token)
+ {
+ if (IsPosix) {
+ if (token == invalidPosix)
+ throw new ArgumentException ("Invalid token");
+
+ _token = token;
+ // apply defaults
+ if (_type == null)
+ _type = "POSIX";
+ // override user choice in this specific case
+ if (_token == IntPtr.Zero)
+ _account = WindowsAccountType.System;
+ }
+ else {
+ if ((token == invalidWindows) && (_account != WindowsAccountType.Anonymous))
+ throw new ArgumentException ("Invalid token");
+
+ _token = token;
+ // apply defaults
+ if (_type == null)
+ _type = "NTLM";
+ }
+ }
+
+ // see mono/mono/metadata/security.c for implementation
+
+ // Many people use reflection to get a user's roles - so many
+ // that's it's hard to say it's an "undocumented" feature -
+ // so we also implement it in Mono :-/
+ // http://www.dotnet247.com/247reference/msgs/39/195403.aspx
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ internal extern static string[] _GetRoles (IntPtr token);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ internal extern static IntPtr GetCurrentToken ();
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern static string GetTokenName (IntPtr token);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern static IntPtr GetUserToken (string username);
}
}
-