C# : ServiceController previliges problem

OrenRozen
OrenRozen used Ask the Experts™
on
I'm using the following line to check for access to services on remote machine.
ServiceController[] _Services = ServiceController.GetServices(TbxIP.Value);

I get privileges exception using this line, but I don't have problem when accessing the remote machine using the services.msc.

(both commands are done from the same machine with admin privileges to the same remote machine.)
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Sudhakar PulivarthiProject Lead - Engineering
Commented:
Hi,
When you want to access remote machine's SCM u have to provide the credentials. In ur case when ur trying to do through services.msc in ur machine the credentials for that remote machine might have been already stored in "Credential Manager". Hence it was possible with out providing the details.

But, when u want to achieve it programatically then u need to impersonate using remote user credentials before GetServices statement.
I am providing the impersonation code written in C#
internal enum LogonType : int
    {
        /// <summary>
        /// This logon type is intended for users who will be interactively using the computer, such as a user being logged on  
        /// by a terminal server, remote shell, or similar process.
        /// This logon type has the additional expense of caching logon information for disconnected operations; 
        /// therefore, it is inappropriate for some client/server applications,
        /// such as a mail server.
        /// </summary>
        LOGON32_LOGON_INTERACTIVE = 2,

        /// <summary>
        /// This logon type is intended for high performance servers to authenticate plaintext passwords.
        /// The LogonUser function does not cache credentials for this logon type.
        /// </summary>
        LOGON32_LOGON_NETWORK = 3,

        /// <summary>
        /// This logon type is intended for batch servers, where processes may be executing on behalf of a user without 
        /// their direct intervention. This type is also for higher performance servers that process many plaintext
        /// authentication attempts at a time, such as mail or Web servers. 
        /// The LogonUser function does not cache credentials for this logon type.
        /// </summary>
        LOGON32_LOGON_BATCH = 4,

        /// <summary>
        /// Indicates a service-type logon. The account provided must have the service privilege enabled. 
        /// </summary>
        LOGON32_LOGON_SERVICE = 5,

        /// <summary>
        /// This logon type is for GINA DLLs that log on users who will be interactively using the computer. 
        /// This logon type can generate a unique audit record that shows when the workstation was unlocked. 
        /// </summary>
        LOGON32_LOGON_UNLOCK = 7,

        /// <summary>
        /// This logon type preserves the name and password in the authentication package, which allows the server to make 
        /// connections to other network servers while impersonating the client. A server can accept plaintext credentials 
        /// from a client, call LogonUser, verify that the user can access the system across the network, and still 
        /// communicate with other servers.
        /// NOTE: Windows NT:  This value is not supported. 
        /// </summary>
        LOGON32_LOGON_NETWORK_CLEARTEXT = 8,

        /// <summary>
        /// This logon type allows the caller to clone its current token and specify new credentials for outbound connections.
        /// The new logon session has the same local identifier but uses different credentials for other network connections. 
        /// NOTE: This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider.
        /// NOTE: Windows NT:  This value is not supported. 
        /// </summary>
        LOGON32_LOGON_NEW_CREDENTIALS = 9,
    }

    /// <summary>
    /// This class provides a wrapper for impersonating a windows user.
    /// </summary>
    public class Impersonation : IDisposable
    {
        // Impersonation object to close later when requested.
        private IntPtr _userHandle;
        private WindowsImpersonationContext _impersonationContext;


        /// <summary>
        /// Starts the impersonate context for the credentials.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="password">The password.</param>
        /// <param name="domain">The domain.</param>
        /// <returns></returns>
        public bool StartImpersonate(string userName, string password, string domain)
        {
            // User machine token.
            _userHandle = IntPtr.Zero;

            //bool loggedOn = LogonUser("prateek.rathore", "SHIVA", "prtk33", 9, 0, out userHandle);
            bool loggedOn = LogonUser(userName, domain, password, 9, 0, out _userHandle);

            // Fails to log on to machine.
            if (!loggedOn)
            {                
                return false;
            }

            try
            {
                // Begin impersonating the user.
                _impersonationContext = WindowsIdentity.Impersonate(_userHandle);
            }
            catch (UnauthorizedAccessException ex)
            {
                throw new Exception(ex.Message);
            }
            catch (OutOfMemoryException ex)
            {
                throw new Exception(ex.Message);
            }
            catch (SecurityException ex)
            {
                throw new Exception(ex.Message);
            }

            return true;
        }

        /// <summary>
        /// Stops the impersonate context.
        /// </summary>
        /// <returns></returns>
        public bool StopImpersonate()
        {
            // Clean up
            if (_userHandle != IntPtr.Zero)
            {
                CloseHandle(_userHandle);
                _userHandle = IntPtr.Zero;
            }

            if (_impersonationContext != null)
            {
                _impersonationContext.Undo();
                _impersonationContext.Dispose();
                _impersonationContext = null;
            }

            return true;
        }

        
        #region IDisposable Members

        public void Dispose()
        {
            // Call to close impersonation.
            StopImpersonate();
            // Suppress the call, not to include this object to finalization queue.
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="Impersonation"/> is reclaimed by garbage collection.
        /// </summary>
        ~Impersonation()
        {
            // Stop if it is not explicitly stopped.
            if (_userHandle != IntPtr.Zero)
            {
                StopImpersonate();
            }
        }

        #endregion


        // All Interop dlls.
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);
    }

Open in new window

// Impersonate the entry.
Impersonation impersonate = new Impersonation();
// Try to login into the system.
bool status = impersonate.StartImpersonate("UserName","Password","Domain");
// Successfully logged on.
if (status)
{
ServiceController[] _Services = ServiceController.GetServices(TbxIP.Value);
// Dispose the entry.
impersonate.StopImpersonate();
}

Open in new window

You should take a look at this project an learn from it

http://www.codeproject.com/KB/cs/svcmgr.aspx?display=Print

Author

Commented:
just to make sure I understand and to clarify:
1. I'm logged in with the domain administrator account to a specific machine.
2. from that machine, I have no problem accessing 3 remote machines services using services.msc.
3. At the same time, using my code, I can access only 2 of the remote machines.

Won't my code use the credentials of the logged on administrator? why use impersonate with the same user account if I'm already logged in to that account?

Thanks.
C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

Sudhakar PulivarthiProject Lead - Engineering
Commented:
Hi,
When an exe is launched it runs with the current logged in user account.
As far as i know we cannot get the password from the credential store. Hence we need to provide the details and also LogOnUser API requires password to get the access token to remote machine.
SCM is specific to the local user account of that machine. So when we want remotely access it, then the priviledge user of that machine can connect to it.

Author

Commented:
appreciate your answer and I'll try the method you supplied to see if ti'll solve my problem.

just one last thing. what is the namespace for the Impersonation method?


Sudhakar PulivarthiProject Lead - Engineering

Commented:
Thank you Oren!
Impersonation is a custom class not a framework lib class. So u can directly keep under your project's namespace itself and use it.
Impersonation is part of the library. If you want to use impersonation without importing functions using interop and making a person class just to do it and less code. You need to use "System.Management" and or use ConnectionOptions or use "System.Security.Principle.WindowsImpersonationContext"

System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();

ServiceController[] _Services = ServiceController.GetServices(TbxIP.Value);

//Your code to display

//End impersonation
impersonationContext.Undo();

Open in new window


Or you can use the WMI method using Management. You can use impersonation here as well if needed this one uses connection options.

using System;
using System.Management;  
namespace WMIQuery_CS
{
	class Main
	{
		static void Main(string[] args)
		{           
			GetWMIStats();
			Console.ReadLine();
		}

		static void GetWMIStats()
		{
			//Connection credentials to the remote computer - 
			//logged in account  must have adminstrator access for a remote machine
			ConnectionOptions oConn = new ConnectionOptions();
			//oConn.Username = "username";
			//oConn.Password = "password";
			string remoteMachineName="localhost";
			System.Management.ManagementScope oMs = new System.Management.ManagementScope("\\\\" +remoteMachineName , oConn);      
			 // pass the name of the service to query
			System.Management.RelatedObjectQuery oQuery = 
				new System.Management.RelatedObjectQuery("Win32_Service.Name='Alerter'");	 
			ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oMs,oQuery);
			ManagementObjectCollection oReturnCollection = oSearcher.Get();   
 	 
			foreach( ManagementObject oReturn in oReturnCollection ) 
				{				 
				Console.WriteLine("Name : " + oReturn["Name"].ToString());		 
				}   						
		}		 
	}
}

Open in new window


There is a lot of way to get what your looking for these ate just a few.


      ...      
Sudhakar PulivarthiProject Lead - Engineering

Commented:
Hi Russell,
Impersonation concept is part of framework, but i was speaking about the class which i had implemented. There is no framework class called Impersonation.

Author

Commented:
Hi,

I've added Sudhakar-Pulivarthi impersonation method to my code and hope test it today at the customer site.

will reply with the results.

Thanks.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial