mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-07-26 07:58:14 +00:00
fix: use SecureString for guest password, validate Pool/CephPool conflict
Set-PveVmGuestPassword now accepts SecureString instead of plain string for the -Password parameter, matching the established pattern in Set-PvePassword. The password is converted via Marshal and zeroed from memory after use. New-PveStorage now validates that -Pool and -CephPool cannot both be specified, since both mapped to the same API key and CephPool silently overwrote Pool. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.New, "PveStorage", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PveStorage))]
|
||||
public class NewPveStorageCmdlet : PveCmdletBase
|
||||
public sealed class NewPveStorageCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The unique storage identifier/name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The storage pool name.")]
|
||||
@@ -80,6 +80,14 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
if (!ShouldProcess(Storage, "Create PVE Storage"))
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrEmpty(Pool) && !string.IsNullOrEmpty(CephPool))
|
||||
{
|
||||
ThrowTerminatingError(new ErrorRecord(
|
||||
new PSArgumentException("Pool and CephPool cannot both be specified. Use Pool for ZFS pools or CephPool for Ceph/RBD pools."),
|
||||
"PoolConflict", ErrorCategory.InvalidArgument, null));
|
||||
return;
|
||||
}
|
||||
|
||||
var session = GetSession();
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Management.Automation;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Vms
|
||||
@@ -12,6 +14,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Set, "PveVmGuestPassword", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class SetPveVmGuestPasswordCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
@@ -33,7 +36,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// <para type="description">The new password for the user.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, HelpMessage = "The new password.")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
public SecureString Password { get; set; } = new SecureString();
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, indicates the password is already in crypted/hashed format.</para>
|
||||
@@ -48,9 +51,20 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
|
||||
var session = GetSession();
|
||||
|
||||
var ptr = Marshal.SecureStringToGlobalAllocUnicode(Password);
|
||||
string plainPassword;
|
||||
try
|
||||
{
|
||||
plainPassword = Marshal.PtrToStringUni(ptr) ?? string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(ptr);
|
||||
}
|
||||
|
||||
WriteVerbose($"Setting password for user '{Username}' on VM {VmId} via guest agent...");
|
||||
var service = new VmService();
|
||||
service.SetGuestPassword(session, Node, VmId, Username, Password, Crypted.IsPresent);
|
||||
service.SetGuestPassword(session, Node, VmId, Username, plainPassword, Crypted.IsPresent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user