/// <summary> /// Set selected properties of a user. /// </summary> /// <param name="userHandle">Handle to an open SAM user.</param> /// <param name="sourceUser"> /// A <see cref="LocalUser"/> object containing the data to set into the user. /// </param> /// <param name="setFlags"> /// A combination of <see cref="UserProperties"/> values indicating the properties to be set. /// </param> /// <param name="password">A <see cref="System.Security.SecureString"/> /// object containing the new password. /// </param> /// <param name="passwordExpired">One of the /// <see cref="PasswordExpiredState"/> enumeration values indicating /// whether the password-expired state is to be explicitly set or /// left as is. If the <paramref name="password"/> parameter is null, /// this parameter is ignored. /// </param> /// <param name="setPasswordNeverExpires"> /// Nullable value the specifies whether the PasswordNeverExpires bit should be flipped /// </param> private void SetUserData(IntPtr userHandle, LocalUser sourceUser, UserProperties setFlags, System.Security.SecureString password, PasswordExpiredState passwordExpired, bool? setPasswordNeverExpires) { IntPtr buffer = IntPtr.Zero; try { UInt32 which = 0; UInt32 status = 0; UInt32 uac = GetUserAccountControl(userHandle); USER_ALL_INFORMATION info = new USER_ALL_INFORMATION(); if (setFlags.HasFlag(UserProperties.AccountExpires)) { which |= SamApi.USER_ALL_ACCOUNTEXPIRES; info.AccountExpires.QuadPart = sourceUser.AccountExpires.HasValue ? sourceUser.AccountExpires.Value.ToFileTime() : 0L; } if (setFlags.HasFlag(UserProperties.Description)) { which |= SamApi.USER_ALL_ADMINCOMMENT; info.AdminComment = new UNICODE_STRING(sourceUser.Description); } if (setFlags.HasFlag(UserProperties.Enabled)) { which |= SamApi.USER_ALL_USERACCOUNTCONTROL; if (sourceUser.Enabled) uac &= ~SamApi.USER_ACCOUNT_DISABLED; else uac |= SamApi.USER_ACCOUNT_DISABLED; } if (setFlags.HasFlag(UserProperties.FullName)) { which |= SamApi.USER_ALL_FULLNAME; info.FullName = new UNICODE_STRING(sourceUser.FullName); } if (setFlags.HasFlag(UserProperties.PasswordNeverExpires)) { // Only modify the bit if a change was requested if (setPasswordNeverExpires.HasValue) { which |= SamApi.USER_ALL_USERACCOUNTCONTROL; if (setPasswordNeverExpires.Value) uac |= SamApi.USER_DONT_EXPIRE_PASSWORD; else uac &= ~SamApi.USER_DONT_EXPIRE_PASSWORD; } } if (setFlags.HasFlag(UserProperties.PasswordRequired)) { which |= SamApi.USER_ALL_USERACCOUNTCONTROL; if (sourceUser.PasswordRequired) uac &= ~SamApi.USER_PASSWORD_NOT_REQUIRED; else uac |= SamApi.USER_PASSWORD_NOT_REQUIRED; } if (which != 0) { info.WhichFields = which; if ((which & SamApi.USER_ALL_USERACCOUNTCONTROL) != 0) info.UserAccountControl = uac; buffer = Marshal.AllocHGlobal(ClrFacade.SizeOf<USER_ALL_INFORMATION>()); ClrFacade.StructureToPtr<USER_ALL_INFORMATION>(info, buffer, false); status = SamApi.SamSetInformationUser(userHandle, USER_INFORMATION_CLASS.UserAllInformation, buffer); ThrowOnFailure(status); status = SamApi.SamFreeMemory(buffer); buffer = IntPtr.Zero; } if (setFlags.HasFlag(UserProperties.UserMayChangePassword)) SetUserMayChangePassword(userHandle, sourceUser.SID, sourceUser.UserMayChangePassword); if (password != null) SetUserPassword(userHandle, password, passwordExpired); } finally { if (buffer != IntPtr.Zero) { ClrFacade.DestroyStructure<USER_ALL_INFORMATION>(buffer); Marshal.FreeHGlobal(buffer); } } }
/// <summary> /// Set a user's password. /// </summary> /// <param name="userHandle">Handle to an open User.</param> /// <param name="password">A <see cref="System.Security.SecureString"/> /// object containing the new password. /// </param> /// <param name="passwordExpired">One of the /// <see cref="PasswordExpiredState"/> enumeration values indicating /// whether the password-expired state is to be explicitly set or /// left as is. /// </param> private void SetUserPassword(IntPtr userHandle, System.Security.SecureString password, PasswordExpiredState passwordExpired) { if (password != null) { USER_SET_PASSWORD_INFORMATION info = new USER_SET_PASSWORD_INFORMATION(); IntPtr buffer = IntPtr.Zero; try { bool setPwExpire = false; switch (passwordExpired) { case PasswordExpiredState.Expired: setPwExpire = true; break; case PasswordExpiredState.NotExpired: setPwExpire = false; break; case PasswordExpiredState.Unchanged: setPwExpire = IsPasswordExpired(userHandle); break; } info.Password = new UNICODE_STRING(password.AsString()); info.PasswordExpired = setPwExpire; buffer = Marshal.AllocHGlobal(Marshal.SizeOf(info)); ClrFacade.StructureToPtr<USER_SET_PASSWORD_INFORMATION>(info, buffer, false); var status = SamApi.SamSetInformationUser(userHandle, USER_INFORMATION_CLASS.UserSetPasswordInformation, buffer); ThrowOnFailure(status); } finally { if (buffer != IntPtr.Zero) { ClrFacade.DestroyStructure<USER_SET_PASSWORD_INFORMATION>(buffer); Marshal.FreeHGlobal(buffer); } } } }
/// <summary> /// Update a local user with new properties. /// </summary> /// <param name="user"> /// A <see cref="LocalUser"/> object representing the user to be updated. /// </param> /// <param name="changed"> /// A LocalUser object containing the desired changes. /// </param> /// <param name="password">A <see cref="System.Security.SecureString"/> /// object containing the new password. A null value in this parameter /// indicates that the password is not to be changed. /// </param> /// <param name="passwordExpired">One of the /// <see cref="PasswordExpiredState"/> enumeration values indicating /// whether the password-expired state is to be explicitly set or /// left as is. /// If the <paramref name="password"/> parameter is null, this parameter /// is ignored. /// </param> /// <param name="setPasswordNeverExpires"> /// Indicates whether the PasswordNeverExpires parameter was specified. /// </param> private void UpdateUser(LocalUser user, LocalUser changed, System.Security.SecureString password, PasswordExpiredState passwordExpired, bool? setPasswordNeverExpires) { UserProperties properties = UserProperties.None; if (user.AccountExpires != changed.AccountExpires) properties |= UserProperties.AccountExpires; if (user.Description != changed.Description) properties |= UserProperties.Description; if (user.FullName != changed.FullName) properties |= UserProperties.FullName; if (setPasswordNeverExpires.HasValue) properties |= UserProperties.PasswordNeverExpires; if (user.UserMayChangePassword != changed.UserMayChangePassword) properties |= UserProperties.UserMayChangePassword; if (user.PasswordRequired != changed.PasswordRequired) properties |= UserProperties.PasswordRequired; if ( properties != UserProperties.None || passwordExpired != PasswordExpiredState.Unchanged || password != null) { IntPtr userHandle = IntPtr.Zero; UInt32 status = 0; try { status = SamApi.SamOpenUser(localDomainHandle, Win32.MAXIMUM_ALLOWED, user.SID.GetRid(), out userHandle); ThrowOnFailure(status); SetUserData(userHandle, changed, properties, password, passwordExpired, setPasswordNeverExpires); } finally { if (userHandle != IntPtr.Zero) status = SamApi.SamCloseHandle(userHandle); } } }