/*
* Process Hacker -
* SAM user handle
*
* Copyright (C) 2009 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see .
*/
using System;
using ProcessHacker.Native.Api;
using ProcessHacker.Native.Security;
namespace ProcessHacker.Native.Objects
{
///
/// Represents a handle to a SAM user.
///
public sealed class SamUserHandle : SamHandle
{
public static SamUserHandle Create(SamUserAccess access, SamDomainHandle domainHandle, string name, out int userId)
{
IntPtr handle;
UnicodeString nameStr = new UnicodeString(name);
try
{
Win32.SamCreateUserInDomain(
domainHandle,
ref nameStr,
access,
out handle,
out userId
).ThrowIf();
}
finally
{
nameStr.Dispose();
}
return new SamUserHandle(handle, true);
}
public static SamUserHandle Open(string name, SamUserAccess access)
{
return Open(Sid.FromName(name), access);
}
public static SamUserHandle Open(Sid sid, SamUserAccess access)
{
using (var dhandle = new SamDomainHandle(sid.DomainName, SamDomainAccess.Lookup))
{
return new SamUserHandle(dhandle, dhandle.LookupName(sid.Name), access);
}
}
private SamUserHandle(IntPtr handle, bool owned)
: base(handle, owned)
{ }
public SamUserHandle(SamDomainHandle domainHandle, string name, SamUserAccess access)
: this(domainHandle, domainHandle.LookupName(name), access)
{ }
///
/// Opens a SAM user.
///
/// A handle to a SAM domain.
/// The relative ID of the user to open.
/// The desired access to the user.
public SamUserHandle(SamDomainHandle domainHandle, int userId, SamUserAccess access)
{
IntPtr handle;
Win32.SamOpenUser(
domainHandle,
access,
userId,
out handle
).ThrowIf();
this.Handle = handle;
}
public void ChangePassword(string oldPassword, string newPassword)
{
UnicodeString oldPasswordStr = new UnicodeString(oldPassword);
UnicodeString newPasswordStr = new UnicodeString(newPassword);
try
{
Win32.SamChangePasswordUser(
this,
ref oldPasswordStr,
ref newPasswordStr
).ThrowIf();
}
finally
{
oldPasswordStr.Dispose();
newPasswordStr.Dispose();
}
}
public void Delete()
{
Win32.SamDeleteUser(this).ThrowIf();
}
public string AdminComment
{
get { return this.Information.AdminComment; }
}
public UserAccountFlags Flags
{
get { return this.Information.UserFlags; }
}
public string FullName
{
get
{
using (SamMemoryAlloc data = this.GetInformation(UserInformationClass.UserFullNameInformation))
{
return data.ReadStruct().FullName.Text;
}
}
}
public int[] Groups
{
get
{
IntPtr groups;
int count;
Win32.SamGetGroupsForUser(
this,
out groups,
out count
).ThrowIf();
using (SamMemoryAlloc groupsAlloc = new SamMemoryAlloc(groups))
{
return groupsAlloc.ReadInt32Array(0, count);
}
}
}
public SamUserInformation Information
{
get
{
using (SamMemoryAlloc data = this.GetInformation(UserInformationClass.UserAllInformation))
{
UserAllInformation info = data.ReadStruct();
return new SamUserInformation(
SamDomainHandle.ToDateTime(info.LastLogon),
SamDomainHandle.ToDateTime(info.LastLogoff),
SamDomainHandle.ToDateTime(info.PasswordLastSet),
SamDomainHandle.ToDateTime(info.AccountExpires),
SamDomainHandle.ToDateTime(info.PasswordCanChange),
SamDomainHandle.ToDateTime(info.PasswordMustChange),
info.UserName.Text,
info.FullName.Text,
info.AdminComment.Text,
info.UserComment.Text,
info.UserId,
info.PrimaryGroupId,
info.UserAccountControl,
info.PasswordExpired
);
}
}
}
private SamMemoryAlloc GetInformation(UserInformationClass infoClass)
{
IntPtr buffer;
Win32.SamQueryInformationUser(
this,
infoClass,
out buffer
).ThrowIf();
return new SamMemoryAlloc(buffer);
}
public string Name
{
get
{
using (SamMemoryAlloc data = this.GetInformation(UserInformationClass.UserAccountNameInformation))
{
return data.ReadStruct().UserName.Text;
}
}
}
public string PasswordHint
{
get
{
using (SamMemoryAlloc data = this.GetInformation(UserInformationClass.UserExtendedInformation))
{
return data.ReadStruct().PasswordHint.Text;
}
}
}
public unsafe void SetAdminComment(string comment)
{
UserAllInformation info = new UserAllInformation
{
WhichFields = UserWhichFields.AdminComment,
AdminComment = new UnicodeString(comment)
};
try
{
this.SetInformation(UserInformationClass.UserAllInformation, new IntPtr(&info));
}
finally
{
info.AdminComment.Dispose();
}
}
public unsafe void SetFlags(UserAccountFlags flags)
{
UserAllInformation info = new UserAllInformation
{
WhichFields = UserWhichFields.UserAccountControl,
UserAccountControl = flags
};
this.SetInformation(UserInformationClass.UserAllInformation, new IntPtr(&info));
}
public unsafe void SetFullName(string fullName)
{
UserFullNameInformation info = new UserFullNameInformation
{
FullName = new UnicodeString(fullName)
};
try
{
this.SetInformation(UserInformationClass.UserFullNameInformation, new IntPtr(&info));
}
finally
{
info.FullName.Dispose();
}
}
private void SetInformation(UserInformationClass infoClass, IntPtr buffer)
{
Win32.SamSetInformationUser(
this,
infoClass,
buffer
).ThrowIf();
}
public unsafe void SetPassword(string password, bool expired)
{
UserSetPasswordInformation info = new UserSetPasswordInformation
{
Password = new UnicodeString(password),
PasswordExpired = expired
};
try
{
this.SetInformation(UserInformationClass.UserSetPasswordInformation, new IntPtr(&info));
}
finally
{
info.Password.Dispose();
}
}
public unsafe void SetPasswordHint(string passwordHint)
{
UserExtendedInformation info = new UserExtendedInformation
{
ExtendedWhichFields = UserExtendedWhichFields.PasswordHint,
PasswordHint = new UnicodeString(passwordHint)
};
try
{
this.SetInformation(UserInformationClass.UserExtendedInformation, new IntPtr(&info));
}
finally
{
info.PasswordHint.Dispose();
}
}
}
public class SamUserInformation
{
private readonly DateTime _lastLogon;
private readonly DateTime _lastLogoff;
private readonly DateTime _passwordLastSet;
private readonly DateTime _accountExpires;
private readonly DateTime _passwordCanChange;
private readonly DateTime _passwordMustChange;
private readonly string _userName;
private readonly string _fullName;
private readonly string _adminComment;
private readonly string _userComment;
private readonly int _userId;
private readonly int _primaryGroupId;
private readonly UserAccountFlags _userFlags;
private readonly bool _passwordExpired;
public SamUserInformation(
DateTime lastLogon,
DateTime lastLogoff,
DateTime passwordLastSet,
DateTime accountExpires,
DateTime passwordCanChange,
DateTime passwordMustChange,
string userName,
string fullName,
string adminComment,
string userComment,
int userId,
int primaryGroupId,
UserAccountFlags userFlags,
bool passwordExpired
)
{
_lastLogon = lastLogon;
_lastLogoff = lastLogoff;
_passwordLastSet = passwordLastSet;
_accountExpires = accountExpires;
_passwordCanChange = passwordCanChange;
_passwordMustChange = passwordMustChange;
_userName = userName;
_fullName = fullName;
_adminComment = adminComment;
_userComment = userComment;
_userId = userId;
_primaryGroupId = primaryGroupId;
_userFlags = userFlags;
_passwordExpired = passwordExpired;
}
public DateTime LastLogon { get { return _lastLogon; } }
public DateTime LastLogoff { get { return _lastLogoff; } }
public DateTime PasswordLastSet { get { return _passwordLastSet; } }
public DateTime AccountExpires { get { return _accountExpires; } }
public DateTime PasswordCanChange { get { return _passwordCanChange; } }
public DateTime PasswordMustChange { get { return _passwordMustChange; } }
public string UserName { get { return _userName; } }
public string FullName { get { return _fullName; } }
public string AdminComment { get { return _adminComment; } }
public string UserComment { get { return _userComment; } }
public int UserId { get { return _userId; } }
public int PrimaryGroupId { get { return _primaryGroupId; } }
public UserAccountFlags UserFlags { get { return _userFlags; } }
public bool PasswordExpired { get { return _passwordExpired; } }
}
}