From 7a696678e57917aa94e0557c35b1ed3d00068a77 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 8 Apr 2010 13:43:23 +0100 Subject: [PATCH] Define XML syntax for password expiry This extends the XML syntax for to allow a password expiry time to be set eg The timestamp is in UTC. * src/conf/domain_conf.h: Pull passwd out into separate struct virDomainGraphicsAuthDef to allow sharing between VNC & SPICE * src/conf/domain_conf.c: Add parsing/formatting of new passwdValidTo argument * src/opennebula/one_conf.c, src/qemu/qemu_conf.c, src/qemu/qemu_driver.c, src/xen/xend_internal.c, src/xen/xm_internal.c: Update for changed struct containing VNC password --- docs/formatdomain.html.in | 8 ++- src/conf/domain_conf.c | 104 +++++++++++++++++++++++++++++++++----- src/conf/domain_conf.h | 13 ++++- src/esx/esx_vmx.c | 6 +-- src/opennebula/one_conf.c | 4 +- src/qemu/qemu_conf.c | 4 +- src/qemu/qemu_driver.c | 20 ++++---- src/xen/xend_internal.c | 12 ++--- src/xen/xm_internal.c | 12 ++--- 9 files changed, 136 insertions(+), 47 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index e6a8162f7f..a4ff500e57 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1102,7 +1102,9 @@ qemu-kvm -net nic,model=? /dev/null The listen attribute is an IP address for the server to listen on. The passwd attribute provides a VNC password in clear text. The keymap attribute specifies the keymap - to use. + to use. It is possible to set a limit on the validity of the password + be giving an timestamp passwdValidTo='2010-04-09T15:51:00' + assumed to be in UTC. NB, this may not be supported by all hypervisors.
"spice"
@@ -1114,7 +1116,9 @@ qemu-kvm -net nic,model=? /dev/null The listen attribute is an IP address for the server to listen on. The passwd attribute provides a SPICE password in clear text. The keymap attribute specifies the keymap - to use. + to use. It is possible to set a limit on the validity of the password + be giving an timestamp passwdValidTo='2010-04-09T15:51:00' + assumed to be in UTC. NB, this may not be supported by all hypervisors.
"rdp"
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 1f3bca8cad..b9e4f4c6fd 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -428,6 +428,17 @@ virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms, return obj; } +static void +virDomainGraphicsAuthDefClear(virDomainGraphicsAuthDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->passwd); + + /* Don't free def */ +} + void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def) { if (!def) @@ -437,7 +448,7 @@ void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def) case VIR_DOMAIN_GRAPHICS_TYPE_VNC: VIR_FREE(def->data.vnc.listenAddr); VIR_FREE(def->data.vnc.keymap); - VIR_FREE(def->data.vnc.passwd); + virDomainGraphicsAuthDefClear(&def->data.vnc.auth); break; case VIR_DOMAIN_GRAPHICS_TYPE_SDL: @@ -456,7 +467,7 @@ void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def) case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: VIR_FREE(def->data.spice.listenAddr); VIR_FREE(def->data.spice.keymap); - VIR_FREE(def->data.spice.passwd); + virDomainGraphicsAuthDefClear(&def->data.spice.auth); break; } @@ -3070,6 +3081,55 @@ error: goto cleanup; } + +static int +virDomainGraphicsAuthDefParseXML(xmlNodePtr node, virDomainGraphicsAuthDefPtr def) +{ + char *validTo = NULL; + + def->passwd = virXMLPropString(node, "passwd"); + + if (!def->passwd) + return 0; + + validTo = virXMLPropString(node, "passwdValidTo"); + if (validTo) { + char *tmp; + struct tm tm; + memset(&tm, 0, sizeof(tm)); + /* Expect: YYYY-MM-DDTHH:MM:SS (%d-%d-%dT%d:%d:%d) eg 2010-11-28T14:29:01 */ + if (/* year */ + virStrToLong_i(validTo, &tmp, 10, &tm.tm_year) < 0 || *tmp != '-' || + /* month */ + virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_mon) < 0 || *tmp != '-' || + /* day */ + virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_mday) < 0 || *tmp != 'T' || + /* hour */ + virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_hour) < 0 || *tmp != ':' || + /* minute */ + virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_min) < 0 || *tmp != ':' || + /* second */ + virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_sec) < 0 || *tmp != '\0') { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse password validity time '%s', expect YYYY-MM-DDTHH:MM:SS"), + validTo); + VIR_FREE(validTo); + VIR_FREE(def->passwd); + return -1; + } + VIR_FREE(validTo); + + tm.tm_year -= 1900; /* Human epoch starts at 0 BC, not 1900BC */ + tm.tm_mon--; /* Humans start months at 1, computers at 0 */ + + def->validTo = timegm(&tm); + def->expires = 1; + } + + return 0; +} + + /* Parse the XML definition for a graphics device */ static virDomainGraphicsDefPtr virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) { @@ -3128,8 +3188,10 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) { } def->data.vnc.listenAddr = virXMLPropString(node, "listen"); - def->data.vnc.passwd = virXMLPropString(node, "passwd"); def->data.vnc.keymap = virXMLPropString(node, "keymap"); + + if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0) + goto error; } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) { char *fullscreen = virXMLPropString(node, "fullscreen"); @@ -3253,8 +3315,9 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) { } def->data.spice.listenAddr = virXMLPropString(node, "listen"); - def->data.spice.passwd = virXMLPropString(node, "passwd"); def->data.spice.keymap = virXMLPropString(node, "keymap"); + if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0) + goto error; } cleanup: @@ -6482,6 +6545,27 @@ virDomainTimerDefFormat(virBufferPtr buf, return 0; } +static void +virDomainGraphicsAuthDefFormatAttr(virBufferPtr buf, + virDomainGraphicsAuthDefPtr def, + unsigned int flags) +{ + if (!def->passwd) + return; + + if (flags & VIR_DOMAIN_XML_SECURE) + virBufferEscapeString(buf, " passwd='%s'", + def->passwd); + + if (def->expires) { + char strbuf[100]; + struct tm tmbuf, *tm; + tm = gmtime_r(&def->validTo, &tmbuf); + strftime(strbuf, sizeof(strbuf), "%Y-%m-%dT%H:%M:%S", tm); + virBufferVSprintf(buf, " passwdValidTo='%s'", strbuf); + } +} + static int virDomainGraphicsDefFormat(virBufferPtr buf, virDomainGraphicsDefPtr def, @@ -6517,11 +6601,7 @@ virDomainGraphicsDefFormat(virBufferPtr buf, virBufferEscapeString(buf, " keymap='%s'", def->data.vnc.keymap); - if (def->data.vnc.passwd && - (flags & VIR_DOMAIN_XML_SECURE)) - virBufferEscapeString(buf, " passwd='%s'", - def->data.vnc.passwd); - + virDomainGraphicsAuthDefFormatAttr(buf, &def->data.vnc.auth, flags); break; case VIR_DOMAIN_GRAPHICS_TYPE_SDL: @@ -6588,11 +6668,7 @@ virDomainGraphicsDefFormat(virBufferPtr buf, virBufferEscapeString(buf, " keymap='%s'", def->data.spice.keymap); - if (def->data.spice.passwd && - (flags & VIR_DOMAIN_XML_SECURE)) - virBufferEscapeString(buf, " passwd='%s'", - def->data.spice.passwd); - + virDomainGraphicsAuthDefFormatAttr(buf, &def->data.spice.auth, flags); break; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index c6699e2e54..d66aaa3232 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -517,6 +517,15 @@ enum virDomainGraphicsType { VIR_DOMAIN_GRAPHICS_TYPE_LAST, }; +typedef struct _virDomainGraphicsAuthDef virDomainGraphicsAuthDef; +typedef virDomainGraphicsAuthDef *virDomainGraphicsAuthDefPtr; +struct _virDomainGraphicsAuthDef { + char *passwd; + unsigned int expires: 1; /* Whether there is an expiry time set */ + time_t validTo; /* seconds since epoch */ +}; + + typedef struct _virDomainGraphicsDef virDomainGraphicsDef; typedef virDomainGraphicsDef *virDomainGraphicsDefPtr; struct _virDomainGraphicsDef { @@ -527,7 +536,7 @@ struct _virDomainGraphicsDef { unsigned int autoport :1; char *listenAddr; char *keymap; - char *passwd; + virDomainGraphicsAuthDef auth; } vnc; struct { char *display; @@ -550,7 +559,7 @@ struct _virDomainGraphicsDef { int tlsPort; char *listenAddr; char *keymap; - char *passwd; + virDomainGraphicsAuthDef auth; unsigned int autoport :1; } spice; } data; diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c index 36818dfa96..b6b3954010 100644 --- a/src/esx/esx_vmx.c +++ b/src/esx/esx_vmx.c @@ -1431,7 +1431,7 @@ esxVMX_ParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def) esxUtil_GetConfigString(conf, "RemoteDisplay.vnc.keymap", &(*def)->data.vnc.keymap, true) < 0 || esxUtil_GetConfigString(conf, "RemoteDisplay.vnc.password", - &(*def)->data.vnc.passwd, true) < 0) { + &(*def)->data.vnc.auth.passwd, true) < 0) { goto failure; } @@ -2831,9 +2831,9 @@ esxVMX_FormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer) def->data.vnc.keymap); } - if (def->data.vnc.passwd != NULL) { + if (def->data.vnc.auth.passwd != NULL) { virBufferVSprintf(buffer, "RemoteDisplay.vnc.password = \"%s\"\n", - def->data.vnc.passwd); + def->data.vnc.auth.passwd); } return 0; diff --git a/src/opennebula/one_conf.c b/src/opennebula/one_conf.c index 2079c51f49..0b0a08af11 100644 --- a/src/opennebula/one_conf.c +++ b/src/opennebula/one_conf.c @@ -262,9 +262,9 @@ char* xmlOneTemplate(virDomainDefPtr def) virBufferVSprintf(&buf,",\n port = \"%d\"", def->graphics[i]->data.vnc.port); - if (def->graphics[i]->data.vnc.passwd != NULL) + if (def->graphics[i]->data.vnc.auth.passwd != NULL) virBufferVSprintf(&buf,",\n passwd = \"%s\"", - def->graphics[i]->data.vnc.passwd); + def->graphics[i]->data.vnc.auth.passwd); virBufferAddLit(&buf," ]\n"); diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 2d66da0132..1753544cd8 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -5029,7 +5029,7 @@ int qemudBuildCommandLine(virConnectPtr conn, virBufferVSprintf(&opt, ":%d", def->graphics[0]->data.vnc.port - 5900); - if (def->graphics[0]->data.vnc.passwd || + if (def->graphics[0]->data.vnc.auth.passwd || driver->vncPassword) virBufferAddLit(&opt, ",password"); @@ -5139,7 +5139,7 @@ int qemudBuildCommandLine(virConnectPtr conn, /* In the password case we set it via monitor command, to avoid * making it visible on CLI, so there's no use of password=XXX * in this bit of the code */ - if (!def->graphics[0]->data.spice.passwd && + if (!def->graphics[0]->data.spice.auth.passwd && !driver->spicePassword) virBufferAddLit(&opt, ",disable-ticketing"); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 766de66e81..052f95dacb 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2522,12 +2522,12 @@ qemuInitPasswords(virConnectPtr conn, if ((vm->def->ngraphics == 1) && vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && - (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) { + (vm->def->graphics[0]->data.vnc.auth.passwd || driver->vncPassword)) { qemuDomainObjEnterMonitorWithDriver(driver, vm); ret = qemuMonitorSetVNCPassword(priv->mon, - vm->def->graphics[0]->data.vnc.passwd ? - vm->def->graphics[0]->data.vnc.passwd : + vm->def->graphics[0]->data.vnc.auth.passwd ? + vm->def->graphics[0]->data.vnc.auth.passwd : driver->vncPassword); qemuDomainObjExitMonitorWithDriver(driver, vm); } @@ -8890,19 +8890,19 @@ qemuDomainChangeGraphics(struct qemud_driver *driver, 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); + if (STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd, dev->data.vnc.auth.passwd)) { + VIR_DEBUG("Updating password on VNC server %p %p", dev->data.vnc.auth.passwd, driver->vncPassword); qemuDomainObjEnterMonitorWithDriver(driver, vm); ret = qemuMonitorSetVNCPassword(priv->mon, - dev->data.vnc.passwd ? - dev->data.vnc.passwd : + dev->data.vnc.auth.passwd ? + dev->data.vnc.auth.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; + VIR_FREE(olddev->data.vnc.auth.passwd); + olddev->data.vnc.auth.passwd = dev->data.vnc.auth.passwd; + dev->data.vnc.auth.passwd = NULL; } else { ret = 0; } diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 7cea49323c..81967d438f 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -1789,7 +1789,7 @@ xenDaemonParseSxprGraphicsOld(virConnectPtr conn, goto no_memory; if (vncPasswd && - !(graphics->data.vnc.passwd = strdup(vncPasswd))) + !(graphics->data.vnc.auth.passwd = strdup(vncPasswd))) goto no_memory; if (keymap && @@ -1909,7 +1909,7 @@ xenDaemonParseSxprGraphicsNew(virConnectPtr conn, goto no_memory; if (vncPasswd && - !(graphics->data.vnc.passwd = strdup(vncPasswd))) + !(graphics->data.vnc.auth.passwd = strdup(vncPasswd))) goto no_memory; if (keymap && @@ -5223,8 +5223,8 @@ xenDaemonFormatSxprGraphicsNew(virDomainGraphicsDefPtr def, if (def->data.vnc.listenAddr) virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr); - if (def->data.vnc.passwd) - virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.passwd); + if (def->data.vnc.auth.passwd) + virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.auth.passwd); if (def->data.vnc.keymap) virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap); } @@ -5266,8 +5266,8 @@ xenDaemonFormatSxprGraphicsOld(virDomainGraphicsDefPtr def, if (def->data.vnc.listenAddr) virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr); - if (def->data.vnc.passwd) - virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.passwd); + if (def->data.vnc.auth.passwd) + virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.auth.passwd); if (def->data.vnc.keymap) virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap); diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index a4d1a3097f..4d6b41b032 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -1304,7 +1304,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) { } if (xenXMConfigCopyStringOpt(conf, "vnclisten", &graphics->data.vnc.listenAddr) < 0) goto cleanup; - if (xenXMConfigCopyStringOpt(conf, "vncpasswd", &graphics->data.vnc.passwd) < 0) + if (xenXMConfigCopyStringOpt(conf, "vncpasswd", &graphics->data.vnc.auth.passwd) < 0) goto cleanup; if (xenXMConfigCopyStringOpt(conf, "keymap", &graphics->data.vnc.keymap) < 0) goto cleanup; @@ -1376,7 +1376,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) { if (!(graphics->data.vnc.listenAddr = strdup(key + 10))) goto no_memory; } else if (STRPREFIX(key, "vncpasswd=")) { - if (!(graphics->data.vnc.passwd = strdup(key + 10))) + if (!(graphics->data.vnc.auth.passwd = strdup(key + 10))) goto no_memory; } else if (STRPREFIX(key, "keymap=")) { if (!(graphics->data.vnc.keymap = strdup(key + 7))) @@ -2541,9 +2541,9 @@ virConfPtr xenXMDomainConfigFormat(virConnectPtr conn, xenXMConfigSetString(conf, "vnclisten", def->graphics[0]->data.vnc.listenAddr) < 0) goto no_memory; - if (def->graphics[0]->data.vnc.passwd && + if (def->graphics[0]->data.vnc.auth.passwd && xenXMConfigSetString(conf, "vncpasswd", - def->graphics[0]->data.vnc.passwd) < 0) + def->graphics[0]->data.vnc.auth.passwd) < 0) goto no_memory; if (def->graphics[0]->data.vnc.keymap && xenXMConfigSetString(conf, "keymap", @@ -2572,9 +2572,9 @@ virConfPtr xenXMDomainConfigFormat(virConnectPtr conn, if (def->graphics[0]->data.vnc.listenAddr) virBufferVSprintf(&buf, ",vnclisten=%s", def->graphics[0]->data.vnc.listenAddr); - if (def->graphics[0]->data.vnc.passwd) + if (def->graphics[0]->data.vnc.auth.passwd) virBufferVSprintf(&buf, ",vncpasswd=%s", - def->graphics[0]->data.vnc.passwd); + def->graphics[0]->data.vnc.auth.passwd); if (def->graphics[0]->data.vnc.keymap) virBufferVSprintf(&buf, ",keymap=%s", def->graphics[0]->data.vnc.keymap);