S
smyers
The program I have written to change a password by impersonating an
admin has worked successfully on my local XP, but when transferred to
the Windows 2000 server the impersonation fails. I have tried
everything I can think of even to the extent of making sure the W2k
box has the SE_TCB_NAME privilege and installing a server
certification and the program is still not functioning properly on the
server. I believe that the LogonUser() function is taking in the
correct values with the exception that the token has no value...it
continually is showing an output of 0 when I debug on the server. Any
suggestions would be greatly appreciated. Here is some code:
using System;
using System.DirectoryServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using System.Configuration;
using System.Diagnostics;
namespace BoardShareData
{
public class UserSecurity
{
public UserSecurity()
{
}
#region Impersonate Info
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
private static extern bool LogonUser(
String lpszUsername,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken );
[DllImport("advapi32.dll")]
private static extern bool DuplicateToken(
IntPtr ExistingTokenHandle,
int ImpersonationLevel,
ref IntPtr DuplicateTokenHandle );
#endregion
#region Private Methods
/// <summary>
/// Sets up the impersonation
/// </summary>
/// <returns></returns>
private bool _impersonateValidUser()
{
string adminUser, adminPwd, domain;
// values come from web.config file
domain = Environment.MachineName.ToString();
adminUser = ConfigurationSettings.AppSettings["pwdAdminUser"].ToString();
adminPwd = ConfigurationSettings.AppSettings["pwdAdminPwd"].ToString();
#if (DEBUG)
// debug environment
adminUser = ConfigurationSettings.AppSettings["pwdAdminUser-debug"].ToString();
adminPwd = ConfigurationSettings.AppSettings["pwdAdminPwd-debug"].ToString();
#endif
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
// check to make sure user has rights to change the password
if(LogonUser(adminUser, domain, adminPwd, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != false)
{
if(DuplicateToken(token, 2, ref tokenDuplicate) != false)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
return true;
else
return false;
}
else
return false;
}
else
return false;
}
/// <summary>
/// Undoes the impersonation
/// </summary>
private void _undoImpersonation()
{
impersonationContext.Undo();
}
#endregion
#region Public Methods
// change password for a given user
public void ChangePassword(string userName, string userPwd)
{
if (this._impersonateValidUser())
{
// valid admin user, impersonation is working
// impersonation set up, change the password
string adStr = "WinNT://" + Environment.MachineName.ToString();
DirectoryEntry ad = new DirectoryEntry(adStr);
DirectoryEntry user;
// find user and set password
try
{
user = ad.Children.Find(userName, "User");
user.Invoke("SetPassword", new object[] {userPwd});
user.CommitChanges();
// done with impersonation
this._undoImpersonation();
}
catch (Exception exp)
{
// error encountered, undo impersonation
this._undoImpersonation();
throw exp;
}
}
else
{
// impersonation did not work, some type of error handling here to
let user know what happened
Console.Write("You are not a valid user");
}
}
#endregion
}
}
admin has worked successfully on my local XP, but when transferred to
the Windows 2000 server the impersonation fails. I have tried
everything I can think of even to the extent of making sure the W2k
box has the SE_TCB_NAME privilege and installing a server
certification and the program is still not functioning properly on the
server. I believe that the LogonUser() function is taking in the
correct values with the exception that the token has no value...it
continually is showing an output of 0 when I debug on the server. Any
suggestions would be greatly appreciated. Here is some code:
using System;
using System.DirectoryServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using System.Configuration;
using System.Diagnostics;
namespace BoardShareData
{
public class UserSecurity
{
public UserSecurity()
{
}
#region Impersonate Info
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
private static extern bool LogonUser(
String lpszUsername,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken );
[DllImport("advapi32.dll")]
private static extern bool DuplicateToken(
IntPtr ExistingTokenHandle,
int ImpersonationLevel,
ref IntPtr DuplicateTokenHandle );
#endregion
#region Private Methods
/// <summary>
/// Sets up the impersonation
/// </summary>
/// <returns></returns>
private bool _impersonateValidUser()
{
string adminUser, adminPwd, domain;
// values come from web.config file
domain = Environment.MachineName.ToString();
adminUser = ConfigurationSettings.AppSettings["pwdAdminUser"].ToString();
adminPwd = ConfigurationSettings.AppSettings["pwdAdminPwd"].ToString();
#if (DEBUG)
// debug environment
adminUser = ConfigurationSettings.AppSettings["pwdAdminUser-debug"].ToString();
adminPwd = ConfigurationSettings.AppSettings["pwdAdminPwd-debug"].ToString();
#endif
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
// check to make sure user has rights to change the password
if(LogonUser(adminUser, domain, adminPwd, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != false)
{
if(DuplicateToken(token, 2, ref tokenDuplicate) != false)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
return true;
else
return false;
}
else
return false;
}
else
return false;
}
/// <summary>
/// Undoes the impersonation
/// </summary>
private void _undoImpersonation()
{
impersonationContext.Undo();
}
#endregion
#region Public Methods
// change password for a given user
public void ChangePassword(string userName, string userPwd)
{
if (this._impersonateValidUser())
{
// valid admin user, impersonation is working
// impersonation set up, change the password
string adStr = "WinNT://" + Environment.MachineName.ToString();
DirectoryEntry ad = new DirectoryEntry(adStr);
DirectoryEntry user;
// find user and set password
try
{
user = ad.Children.Find(userName, "User");
user.Invoke("SetPassword", new object[] {userPwd});
user.CommitChanges();
// done with impersonation
this._undoImpersonation();
}
catch (Exception exp)
{
// error encountered, undo impersonation
this._undoImpersonation();
throw exp;
}
}
else
{
// impersonation did not work, some type of error handling here to
let user know what happened
Console.Write("You are not a valid user");
}
}
#endregion
}
}