2004-04-13 Sebastien Pouliot <sebastien@ximian.com>
authorSebastien Pouliot <sebastien@ximian.com>
Tue, 13 Apr 2004 11:35:42 +0000 (11:35 -0000)
committerSebastien Pouliot <sebastien@ximian.com>
Tue, 13 Apr 2004 11:35:42 +0000 (11:35 -0000)
* WindowsIdentity.cs: Implemented for both Windows and Linux. Fix bug
#52532. Class is only missing serialization bits.
* WindowsImpersonationContext.cs: Implemented for both Windows and
Linux. Fix bug #52532.
* WindowsPrincipal.cs: Implemented for both Windows and Linux.  Fix
bug #52532.

svn path=/trunk/mcs/; revision=25395

mcs/class/corlib/System.Security.Principal/ChangeLog
mcs/class/corlib/System.Security.Principal/WindowsIdentity.cs
mcs/class/corlib/System.Security.Principal/WindowsImpersonationContext.cs
mcs/class/corlib/System.Security.Principal/WindowsPrincipal.cs

index a1ee43acb0a5448ff680259423fe1e4785cd241b..138581fdd02ee033ad4e5baf47d38cded13d1c54 100644 (file)
@@ -1,3 +1,12 @@
+2004-04-13  Sebastien Pouliot  <sebastien@ximian.com>
+
+       * WindowsIdentity.cs: Implemented for both Windows and Linux. Fix bug
+       #52532. Class is only missing serialization bits.
+       * WindowsImpersonationContext.cs: Implemented for both Windows and 
+       Linux. Fix bug #52532.
+       * WindowsPrincipal.cs: Implemented for both Windows and Linux.  Fix 
+       bug #52532.
+
 2003-12-29  Sebastien Pouliot  <spouliot@videotron.ca>
 
        * PrincipalPolicy.cs: Added missing [Serializable] to enum.
index d0c296ec0841ad37792c88ae7e06c55974460f0b..40e158bebf2381c6eda08f5582dfb71acfacc61d 100644 (file)
@@ -3,13 +3,15 @@
 //
 // 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)
+// (C) 2004 Novell (http://www.novell.com)
 //
 
 using System;
+using System.Runtime.CompilerServices;
 using System.Runtime.Serialization;
 
 namespace System.Security.Principal {
@@ -26,45 +28,68 @@ namespace System.Security.Principal {
                private bool _authenticated;
                private string _name;
 
+               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) 
-                       : this (userToken, "NTLM", WindowsAccountType.Normal, false) {}
+                       : this (userToken, null, WindowsAccountType.Normal, false)
+               {
+               }
 
                public WindowsIdentity (IntPtr userToken, string type) 
-                       : this (userToken, type, WindowsAccountType.Normal, false) {}
+                       : this (userToken, type, WindowsAccountType.Normal, false)
+               {
+               }
 
                public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType)
-                       : this (userToken, type, acctType, false) {}
+                       : this (userToken, type, acctType, false)
+               {
+               }
 
                public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
                {
-                       if (userToken == IntPtr.Zero)
-                               throw new ArgumentException ("Invalid token");
-
-                       _token = userToken;
                        _type = type;
                        _account = acctType;
                        _authenticated = isAuthenticated;
                        _name = null;
+                       // last - as it can override some fields
+                       SetToken (userToken);
                }
 #if !NET_1_0
                public WindowsIdentity (string sUserPrincipalName) 
-                       : this (sUserPrincipalName, null) {}
+                       : this (sUserPrincipalName, null)
+               {
+               }
 
-               [MonoTODO]
                public WindowsIdentity (string sUserPrincipalName, string type)
                {
                        if (sUserPrincipalName == null)
                                throw new NullReferenceException ("sUserPrincipalName");
 
-                       throw new ArgumentException ("only for Windows Server 2003 +");
+                       // 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) {}
+               public WindowsIdentity (SerializationInfo info, StreamingContext context)
+               {
+               }
 #endif
-               [MonoTODO]
+
                ~WindowsIdentity ()
                {
+                       // clear our copy but don't close it
+                       // http://www.develop.com/kbrown/book/html/whatis_windowsprincipal.html
                        _token = IntPtr.Zero;
                }
 
@@ -72,17 +97,25 @@ namespace System.Security.Principal {
 
                public static WindowsIdentity GetAnonymous ()
                {
-                       WindowsIdentity id = new WindowsIdentity ((IntPtr)1, String.Empty, WindowsAccountType.Anonymous, false);
-                       // special case
-                       id._token = IntPtr.Zero;
-                       id._name = String.Empty;
+                       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 ()
                {
-                       throw new NotImplementedException ();
+                       return new WindowsIdentity (GetCurrentToken (), null, WindowsAccountType.Normal, true);
                }
 
                // methods
@@ -124,13 +157,12 @@ namespace System.Security.Principal {
                        get { return (_account == WindowsAccountType.System); }
                }
 
-               [MonoTODO ("resolve missing")]
                public virtual string Name
                {
                        get {
                                if (_name == null) {
-                                       // TODO: resolve name from token
-                                       throw new NotImplementedException ();
+                                       // revolve name (runtime)
+                                       _name = GetTokenName (_token);
                                }
                                return _name; 
                        }
@@ -153,6 +185,51 @@ namespace System.Security.Principal {
                        throw new NotImplementedException ();
                }
 #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);
        }
 }
-
index a20c1b78e5758fd52eee9c3cd3ae1535887744d8..6f772d498c466f0c2b42df11a8ed03165ed94b52 100644 (file)
@@ -3,35 +3,63 @@
 //
 // Authors:
 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//     Sebastien Pouliot  (sebastien@ximian.com)
 //
 // (C) 2002 Ximian, Inc (http://www.ximian.com)
+// (C) 2004 Novell (http://www.novell.com)
 //
 
 using System;
+using System.Runtime.CompilerServices;
+using System.Security;
+
+namespace System.Security.Principal {
+
+       public class WindowsImpersonationContext {
 
-namespace System.Security.Principal
-{
-       [MonoTODO]
-       public class WindowsImpersonationContext
-       {
                private IntPtr _token;
+               private bool undo;
 
                internal WindowsImpersonationContext (IntPtr token)
                {
-                       _token = token;
-                       throw new NotImplementedException ();
+                       // we get a copy to control it's lifetime
+                       _token = DuplicateToken (token);
+                       if (!SetCurrentToken (token)) {
+                               throw new SecurityException ("Couldn't impersonate token.");
+                       }
+                       undo = false;
                }
 
                ~WindowsImpersonationContext ()
                {
-                       _token = (IntPtr) 0;
+                       if (!undo) {
+                               Undo ();
+                       }
                }
 
-               [MonoTODO]
                public void Undo ()
                {
-                       throw new NotImplementedException ();
+                       if (!RevertToSelf ()) {
+                               CloseToken (_token);
+                               throw new SecurityException ("Couldn't switch back to original token.");
+                       }
+                       CloseToken (_token);
+                       undo = true;
+                       GC.SuppressFinalize (this);
                }
+
+               // see mono/mono/metadata/security.c for implementation
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static bool CloseToken (IntPtr token);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static IntPtr DuplicateToken (IntPtr token);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static bool SetCurrentToken (IntPtr token);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static bool RevertToSelf ();
        }
 }
-
index ec0e25305336657ca2953f12a4d39bfe9909f5f6..c85cd92cfd269dd546b3e97283ed36d344695fde 100755 (executable)
@@ -2,12 +2,15 @@
 // WindowsPrincipal.cs: Windows IPrincipal implementation
 //
 // Author:
-//     Sebastien Pouliot (spouliot@motus.com)
+//     Sebastien Pouliot (sebastien@ximian.com)
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// (C) 2004 Novell (http://www.novell.com)
 //
 
 using System;
+using System.Collections;
+using System.Runtime.CompilerServices;
 
 namespace System.Security.Principal {
 
@@ -15,6 +18,11 @@ namespace System.Security.Principal {
        public class WindowsPrincipal : IPrincipal {
 
                private WindowsIdentity _identity;
+               // http://groups.google.ca/groups?q=WindowsPrincipal+m_roles&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=OghXf4OgCHA.4228%40tkmsftngp08&rnum=4
+               private string [] m_roles;
+
+               // case sensitivity versus number of groups
+               // http://groups.google.ca/groups?q=WindowsPrincipal+m_roles&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=%23JEMHsMQCHA.1916%40tkmsftngp13&rnum=5
 
                public WindowsPrincipal (WindowsIdentity ntIdentity)
                {
@@ -32,28 +40,116 @@ namespace System.Security.Principal {
 
                // methods
 
-               [MonoTODO]
                public virtual bool IsInRole (int rid) 
                {
-                       throw new NotImplementedException ();
+                       if (IsPosix) {
+                               return IsMemberOfGroupId (Token, (IntPtr) rid);
+                       }
+                       else {
+                               string role = null;
+                               switch (rid) {
+                                       case 544: // Administrator
+                                               role = "BUILTIN\\Administrators";
+                                               break;
+                                       case 545: // User
+                                               role = "BUILTIN\\Users";
+                                               break;
+                                       case 546: // Guest
+                                               role = "BUILTIN\\Guests";
+                                               break;
+                                       case 547: // PowerUser
+                                               role = "BUILTIN\\Power Users";
+                                               break;
+                                       case 548: // AccountOperator
+                                               role = "BUILTIN\\Account Operators";
+                                               break;
+                                       case 549: // SystemOperator
+                                               role = "BUILTIN\\System Operators";
+                                               break;
+                                       case 550: // PrintOperator
+                                               role = "BUILTIN\\Print Operators";
+                                               break;
+                                       case 551: // BackupOperator
+                                               role = "BUILTIN\\Backup Operators";
+                                               break;
+                                       case 552: // Replicator
+                                               role = "BUILTIN\\Replicator";
+                                               break;
+                                       default:
+                                               return false;
+                               }
+                               return IsInRole (role);
+                       }
                }
 
-               [MonoTODO]
                public virtual bool IsInRole (string role)
                {
                        if (role == null)
                                return false;   // ArgumentNullException
+
+                       if (IsPosix) {
+                               // note: Posix is always case-sensitive
+                               return IsMemberOfGroupName (Token, role);
+                       }
+                       else {
+                               // Windows specific code that
+                               // (a) build the role cache like the MS framework (for compatibility)
+                               // (b) case sensitive (for Fx 1.0) and case insensitive (later Fx)
+                               if (m_roles == null) {
+                                       m_roles = WindowsIdentity._GetRoles (Token);
+                               }
+#if !NET_1_0
+                               role = role.ToUpper ();
+#endif
+                               foreach (string check in m_roles) {
 #if NET_1_0
-                       // case sensitive (for 1.0)
+                                       if (role == check)
+                                               return true;
 #else
-                       // case insensitive (for 1.1 and later)
+                                       Console.WriteLine ("> {0}", check);
+                                       if ((check != null) && (role == check.ToUpper ()))
+                                               return true;
 #endif
-                       throw new NotImplementedException ();
+                               }
+                               return false;
+                       }
                }
 
                public virtual bool IsInRole (WindowsBuiltInRole role)
                {
-                       return IsInRole ((int)role);
+                       if (IsPosix) {
+                               // right now we only map Administrator == root
+                               string group = null;
+                               switch (role) {
+                                       case WindowsBuiltInRole.Administrator:
+                                               group = "root";
+                                               break;
+                                       default:
+                                               return false;
+                               }
+                               return IsInRole (group);
+                       }
+                       else {
+                               return IsInRole ((int) role);
+                       }
+               }
+
+               private static bool IsPosix {
+                       get { return ((int) Environment.Platform == 128); }
                }
+
+               private IntPtr Token {
+                       get { return (_identity as WindowsIdentity).Token; }
+               }
+
+               // see mono/mono/metadata/security.c for implementation
+
+               // note: never called by Win32 code (i.e. always return false)
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static bool IsMemberOfGroupId (IntPtr user, IntPtr group);
+
+               // note: never called by Win32 code (i.e. always return false)
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static bool IsMemberOfGroupName (IntPtr user, string group);
        }
 }