mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 11:31:16 +00:00
Implement VNC password change in QEMU
Use the new virDomainUpdateDeviceFlags API to allow the VNC password to be changed on the fly * src/internal.h: Define STREQ_NULLABLE() which is like STREQ() but does not crash if either argument is NULL, and treats two NULLs as equal. * src/libvirt_private.syms: Export virDomainGraphicsTypeToString * src/qemu/qemu_driver.c: Support VNC password change on a live machine * src/qemu/qemu_monitor.c: Disable crazy debugging info. Treat a NULL password as "" (empty string), allowing passwords to be disabled in the monitor
This commit is contained in:
parent
c85f641390
commit
ab952024f4
@ -58,6 +58,12 @@
|
|||||||
# define STRCASENEQLEN(a,b,n) (strncasecmp(a,b,n) != 0)
|
# define STRCASENEQLEN(a,b,n) (strncasecmp(a,b,n) != 0)
|
||||||
# define STRPREFIX(a,b) (strncmp(a,b,strlen(b)) == 0)
|
# define STRPREFIX(a,b) (strncmp(a,b,strlen(b)) == 0)
|
||||||
|
|
||||||
|
# define STREQ_NULLABLE(a, b) \
|
||||||
|
((!(a) && !(b)) || ((a) && (b) && STREQ((a), (b))))
|
||||||
|
# define STRNEQ_NULLABLE(a, b) \
|
||||||
|
((!(a) ^ !(b)) || ((a) && (b) && STRNEQ((a), (b))))
|
||||||
|
|
||||||
|
|
||||||
# define NUL_TERMINATE(buf) do { (buf)[sizeof(buf)-1] = '\0'; } while (0)
|
# define NUL_TERMINATE(buf) do { (buf)[sizeof(buf)-1] = '\0'; } while (0)
|
||||||
# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
|
# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ virDomainFindByName;
|
|||||||
virDomainFindByUUID;
|
virDomainFindByUUID;
|
||||||
virDomainGetRootFilesystem;
|
virDomainGetRootFilesystem;
|
||||||
virDomainGraphicsTypeFromString;
|
virDomainGraphicsTypeFromString;
|
||||||
|
virDomainGraphicsTypeToString;
|
||||||
virDomainGraphicsDefFree;
|
virDomainGraphicsDefFree;
|
||||||
virDomainHostdevDefFree;
|
virDomainHostdevDefFree;
|
||||||
virDomainHostdevModeTypeToString;
|
virDomainHostdevModeTypeToString;
|
||||||
|
@ -7046,6 +7046,83 @@ static int qemudDomainAttachDeviceFlags(virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virDomainGraphicsDefPtr qemuDomainFindGraphics(virDomainObjPtr vm,
|
||||||
|
virDomainGraphicsDefPtr dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < vm->def->ngraphics ; i++) {
|
||||||
|
if (vm->def->graphics[i]->type == dev->type)
|
||||||
|
return vm->def->graphics[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainChangeGraphics(struct qemud_driver *driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainGraphicsDefPtr dev)
|
||||||
|
{
|
||||||
|
virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (!olddev) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("cannot find existing graphics device to modify"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dev->type) {
|
||||||
|
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
|
||||||
|
if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
|
||||||
|
(!dev->data.vnc.autoport && (olddev->data.vnc.port != dev->data.vnc.port))) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("cannot change port settings on vnc graphics"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (STRNEQ_NULLABLE(olddev->data.vnc.listenAddr, dev->data.vnc.listenAddr)) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("cannot change listen address setting on vnc graphics"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("cannot change keymap setting on vnc graphics"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STRNEQ_NULLABLE(olddev->data.vnc.passwd, dev->data.vnc.passwd)) {
|
||||||
|
VIR_DEBUG("Updating password on VNC server %p %p", dev->data.vnc.passwd, driver->vncPassword);
|
||||||
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||||
|
ret = qemuMonitorSetVNCPassword(priv->mon,
|
||||||
|
dev->data.vnc.passwd ?
|
||||||
|
dev->data.vnc.passwd :
|
||||||
|
driver->vncPassword);
|
||||||
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
|
|
||||||
|
/* Steal the new dev's char * reference */
|
||||||
|
VIR_FREE(olddev->data.vnc.passwd);
|
||||||
|
olddev->data.vnc.passwd = dev->data.vnc.passwd;
|
||||||
|
dev->data.vnc.passwd = NULL;
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("unable to change config on '%s' graphics type"),
|
||||||
|
virDomainGraphicsTypeToString(dev->type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
|
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
|
||||||
const char *xml,
|
const char *xml,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
@ -7134,6 +7211,10 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case VIR_DOMAIN_DEVICE_GRAPHICS:
|
||||||
|
ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||||
_("disk device type '%s' cannot be updated"),
|
_("disk device type '%s' cannot be updated"),
|
||||||
|
@ -39,7 +39,8 @@
|
|||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||||
|
|
||||||
#define QEMU_DEBUG_RAW_IO 0
|
#define DEBUG_IO 0
|
||||||
|
#define DEBUG_RAW_IO 0
|
||||||
|
|
||||||
struct _qemuMonitor {
|
struct _qemuMonitor {
|
||||||
virMutex lock;
|
virMutex lock;
|
||||||
@ -302,7 +303,8 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
|
|||||||
if (mon->msg && mon->msg->txOffset == mon->msg->txLength)
|
if (mon->msg && mon->msg->txOffset == mon->msg->txLength)
|
||||||
msg = mon->msg;
|
msg = mon->msg;
|
||||||
|
|
||||||
#if QEMU_DEBUG_RAW_IO
|
#if DEBUG_IO
|
||||||
|
#if DEBUG_RAW_IO
|
||||||
char *str1 = qemuMonitorEscapeNonPrintable(msg ? msg->txBuffer : "");
|
char *str1 = qemuMonitorEscapeNonPrintable(msg ? msg->txBuffer : "");
|
||||||
char *str2 = qemuMonitorEscapeNonPrintable(mon->buffer);
|
char *str2 = qemuMonitorEscapeNonPrintable(mon->buffer);
|
||||||
VIR_ERROR("Process %d %p %p [[[[%s]]][[[%s]]]", (int)mon->bufferOffset, mon->msg, msg, str1, str2);
|
VIR_ERROR("Process %d %p %p [[[[%s]]][[[%s]]]", (int)mon->bufferOffset, mon->msg, msg, str1, str2);
|
||||||
@ -311,6 +313,8 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
|
|||||||
#else
|
#else
|
||||||
VIR_DEBUG("Process %d", (int)mon->bufferOffset);
|
VIR_DEBUG("Process %d", (int)mon->bufferOffset);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
if (mon->json)
|
if (mon->json)
|
||||||
len = qemuMonitorJSONIOProcess(mon,
|
len = qemuMonitorJSONIOProcess(mon,
|
||||||
mon->buffer, mon->bufferOffset,
|
mon->buffer, mon->bufferOffset,
|
||||||
@ -332,7 +336,9 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
|
|||||||
VIR_FREE(mon->buffer);
|
VIR_FREE(mon->buffer);
|
||||||
mon->bufferOffset = mon->bufferLength = 0;
|
mon->bufferOffset = mon->bufferLength = 0;
|
||||||
}
|
}
|
||||||
|
#if DEBUG_IO
|
||||||
VIR_DEBUG("Process done %d used %d", (int)mon->bufferOffset, len);
|
VIR_DEBUG("Process done %d used %d", (int)mon->bufferOffset, len);
|
||||||
|
#endif
|
||||||
if (msg && msg->finished)
|
if (msg && msg->finished)
|
||||||
virCondBroadcast(&mon->notify);
|
virCondBroadcast(&mon->notify);
|
||||||
return len;
|
return len;
|
||||||
@ -455,7 +461,9 @@ qemuMonitorIORead(qemuMonitorPtr mon)
|
|||||||
mon->buffer[mon->bufferOffset] = '\0';
|
mon->buffer[mon->bufferOffset] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG_IO
|
||||||
VIR_DEBUG("Now read %d bytes of data", (int)mon->bufferOffset);
|
VIR_DEBUG("Now read %d bytes of data", (int)mon->bufferOffset);
|
||||||
|
#endif
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -485,7 +493,9 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) {
|
|||||||
|
|
||||||
qemuMonitorLock(mon);
|
qemuMonitorLock(mon);
|
||||||
qemuMonitorRef(mon);
|
qemuMonitorRef(mon);
|
||||||
|
#if DEBUG_IO
|
||||||
VIR_DEBUG("Monitor %p I/O on watch %d fd %d events %d", mon, watch, fd, events);
|
VIR_DEBUG("Monitor %p I/O on watch %d fd %d events %d", mon, watch, fd, events);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (mon->fd != fd || mon->watch != watch) {
|
if (mon->fd != fd || mon->watch != watch) {
|
||||||
VIR_ERROR("event from unexpected fd %d!=%d / watch %d!=%d", mon->fd, fd, mon->watch, watch);
|
VIR_ERROR("event from unexpected fd %d!=%d / watch %d!=%d", mon->fd, fd, mon->watch, watch);
|
||||||
@ -981,6 +991,9 @@ int qemuMonitorSetVNCPassword(qemuMonitorPtr mon,
|
|||||||
int ret;
|
int ret;
|
||||||
DEBUG("mon=%p, fd=%d", mon, mon->fd);
|
DEBUG("mon=%p, fd=%d", mon, mon->fd);
|
||||||
|
|
||||||
|
if (!password)
|
||||||
|
password = "";
|
||||||
|
|
||||||
if (mon->json)
|
if (mon->json)
|
||||||
ret = qemuMonitorJSONSetVNCPassword(mon, password);
|
ret = qemuMonitorJSONSetVNCPassword(mon, password);
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user