I wrote a C# application that unlocks users when they are locked out of their account (Active Directory). The application searches for users in a specific OU and will list t
This code will allow you to call another executable and run it is an administrator.
try
{
path = path_to_your_executable;
ProcessStartInfo myProcess = new ProcessStartInfo(path);
myProcess.Domain = domain;
myProcess.UserName = username;
myProcess.Password = password;
myProcess.UseShellExecute = false;
Process.Start(myProcess);
}
catch (Exception myException)
{
// error handling
}
Not exactly what you're looking for but it is a possible solution.
The goal behind this application strikes me as wrong. You are basically trying to create a means of allowing non-admin users to unlock accounts...which is, for good reason, a feature not available to normal users.
You cannot use a Windows Service (easily), since a Windows Service cannot have a GUI. The only way to do this as a service would be to install the service, and then make a GUI app that used IPC to communicate the request to the service. This would open up a potential loophole, though.
If you're running on Vista, a good option would be to edit the manifest file and add requireAdministrator.
Edit:
It sounds like my first suggestion may be what you want... To do this, the basic process is:
You could then run the client as a normal user (since it just needs to talk to the service, it does not do anything that requires permissions).
You don't have to use a windows service to do something as someone else. You can use impersonation to login as another user to do the actual switch. Here’s an example I found that uses the windows dll "advapi32.dll" to login.
Grab the sample code off the bottom of the page. I didn’t want to just copy his code here.
http://csharptuning.blogspot.com/2007/06/impersonation-in-c.html
One cavet with Impersonation though is that the computer doing the impersonation needs to be on the same domain as the user that your impersonating.
Here is the class I use to perform impersonation on a ASP.NET 2.0 website, running on Windows 2000.
Example Usage:
if (iu.impersonateValidUser("AdminUserName", "DomainName", "AdminPassword"))
{
// Do Something Under Other Users Security Context
iu.undoImpersonation();
}
That's it... Complete class below.
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
public class ImpersonateUser
{
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
public bool impersonateValidUser(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
public void undoImpersonation()
{
impersonationContext.Undo();
}
}
I have a very similar widget on my intranet site, so members of the IT department located in different time zones can handle password resets that also performs a account unlock when the domain admins on the west coast are not available. This is a pretty simple tasks and here is an except of how I did this...
using System.DirectoryServices;
// Impersonate the Admin to Reset the Password / Unlock Account //
// Change variables below.
ImpersonateUser iu = new ImpersonateUser();
if (iu.impersonateValidUser("AdminUserName", "DomainName", "AdminPassword"))
{
resetPassword("AdminUserName", "AdminPassword", UserToReset, "NewPassword");
iu.undoImpersonation();
}
// Perform the Reset / Unlock //
public void resetPassword(string username, string password, string acct, string newpassword)
{
string Path = // LDAP Connection String
string Username = username;
string Password = password;
string Domain = "DomainName\\"; // Change to your domain name
DirectoryEntry de = new DirectoryEntry(Path, Domain + Username, Password, AuthenticationTypes.Secure);
DirectorySearcher ds = new DirectorySearcher(de);
ds.Filter = "(&(objectClass=user)(|(sAMAccountName=" + acct + ")))";
ds.PropertiesToLoad.Add("displayName");
ds.PropertiesToLoad.Add("sAMAccountName");
ds.PropertiesToLoad.Add("DistinguishedName");
ds.PropertiesToLoad.Add("CN");
SearchResult result = ds.FindOne();
string dn = result.Properties["DistinguishedName"][0].ToString();
DirectoryEntry uEntry = new DirectoryEntry("LDAP://" + dn, username, password);
uEntry.Invoke("SetPassword", new object[] { newpassword });
uEntry.Properties["LockOutTime"].Value = 0;
uEntry.CommitChanges();
uEntry.Close();
}
I strongly agree that this can lead to security issues if incorrectly used, we have every change logged and emailed to the domain admins (so their in the loop) and we auto generate the passwords. This has been a huge help for our small IT department, since admins no longer have to wake up at 4 AM to reset a password.