diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 361db299a5..0dea7ebfa4 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -2240,3 +2240,88 @@ qemuAgentSetUserPassword(qemuAgentPtr mon, VIR_FREE(password64); return ret; } + +int +qemuAgentGetUsers(qemuAgentPtr mon, + virTypedParameterPtr *params, + int *nparams, + int *maxparams) +{ + VIR_AUTOPTR(virJSONValue) cmd = NULL; + VIR_AUTOPTR(virJSONValue) reply = NULL; + virJSONValuePtr data = NULL; + size_t ndata; + size_t i; + + if (!(cmd = qemuAgentMakeCommand("guest-get-users", NULL))) + return -1; + + if (qemuAgentCommand(mon, cmd, &reply, true, + VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + return -1; + + if (!(data = virJSONValueObjectGetArray(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("guest-get-users reply was missing return data")); + return -1; + } + + if (!virJSONValueIsArray(data)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed guest-get-users data array")); + return -1; + } + + ndata = virJSONValueArraySize(data); + + if (virTypedParamsAddUInt(params, nparams, maxparams, + "user.count", ndata) < 0) + return -1; + + for (i = 0; i < ndata; i++) { + virJSONValuePtr entry = virJSONValueArrayGet(data, i); + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; + const char *strvalue; + double logintime; + + if (!entry) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("array element missing in guest-get-users return " + "value")); + return -1; + } + + if (!(strvalue = virJSONValueObjectGetString(entry, "user"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("'user' missing in reply of guest-get-users")); + return -1; + } + + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "user.%zu.name", i); + if (virTypedParamsAddString(params, nparams, maxparams, + param_name, strvalue) < 0) + return -1; + + /* 'domain' is only present for windows guests */ + if ((strvalue = virJSONValueObjectGetString(entry, "domain"))) { + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, + "user.%zu.domain", i); + if (virTypedParamsAddString(params, nparams, maxparams, + param_name, strvalue) < 0) + return -1; + } + + if (virJSONValueObjectGetNumberDouble(entry, "login-time", &logintime) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("'login-time' missing in reply of guest-get-users")); + return -1; + } + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, + "user.%zu.login-time", i); + if (virTypedParamsAddULLong(params, nparams, maxparams, + param_name, logintime * 1000) < 0) + return -1; + } + + return ndata; +} diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index 6ae9fe54da..9b36427ee7 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -120,3 +120,8 @@ int qemuAgentSetUserPassword(qemuAgentPtr mon, const char *user, const char *password, bool crypted); + +int qemuAgentGetUsers(qemuAgentPtr mon, + virTypedParameterPtr *params, + int *nparams, + int *maxparams); diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c index 2f79986207..81e0c41e61 100644 --- a/tests/qemuagenttest.c +++ b/tests/qemuagenttest.c @@ -902,6 +902,153 @@ testQemuAgentGetInterfaces(const void *data) return ret; } +static const char testQemuAgentUsersResponse[] = + "{\"return\": " + " [" + " {\"user\": \"test\"," + " \"login-time\": 1561739203.584038" + " }," + " {\"user\": \"test2\"," + " \"login-time\": 1561739229.190697" + " }" + " ]" + "}"; + +static const char testQemuAgentUsersResponse2[] = + "{\"return\": " + " [" + " {\"user\": \"test\"," + " \"domain\": \"DOMAIN\"," + " \"login-time\": 1561739203.584038" + " }" + " ]" + "}"; + +static int +checkUserInfo(virTypedParameterPtr params, + int nparams, + size_t nth, + const char *expUsername, + const char *expDomain, + unsigned long long expLogintime) +{ + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; + const char *username = NULL; + const char *domain = NULL; + unsigned long long logintime = 0; + + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, + "user.%zu.name", nth); + if (virTypedParamsGetString(params, nparams, param_name, &username) < 0) + return -1; + + if (STRNEQ_NULLABLE(expUsername, username)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Expected user name '%s', got '%s'", + expUsername, username); + return -1; + } + + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, + "user.%zu.domain", nth); + virTypedParamsGetString(params, nparams, param_name, &domain); + if (STRNEQ_NULLABLE(expDomain, domain)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Expected domain '%s', got '%s'", + NULLSTR(expDomain), NULLSTR(domain)); + return -1; + } + + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, + "user.%zu.login-time", nth); + if (virTypedParamsGetULLong(params, nparams, param_name, &logintime) < 0) + return -1; + + if (expLogintime != logintime) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Expected login time of '%llu', got '%llu'", + expLogintime, logintime); + return -1; + } + + return 0; +} + +static int +testQemuAgentUsers(const void *data) +{ + virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt); + virTypedParameterPtr params = NULL; + int nparams = 0; + int maxparams = 0; + int ret = -1; + unsigned int count; + + if (!test) + return -1; + + if (qemuMonitorTestAddAgentSyncResponse(test) < 0) + goto cleanup; + + if (qemuMonitorTestAddItem(test, "guest-get-users", + testQemuAgentUsersResponse) < 0) + goto cleanup; + + /* get users */ + if (qemuAgentGetUsers(qemuMonitorTestGetAgent(test), + ¶ms, &nparams, &maxparams) < 0) + goto cleanup; + + if (virTypedParamsGetUInt(params, nparams, "user.count", &count) < 0) + goto cleanup; + if (count != 2) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Expected '2' users, got '%u'", count); + goto cleanup; + } + + if (checkUserInfo(params, nparams, 0, "test", NULL, 1561739203584) < 0 || + checkUserInfo(params, nparams, 1, "test2", NULL, 1561739229190) < 0) + goto cleanup; + + if (qemuMonitorTestAddAgentSyncResponse(test) < 0) + goto cleanup; + + if (qemuMonitorTestAddItem(test, "guest-get-users", + testQemuAgentUsersResponse2) < 0) + goto cleanup; + + virTypedParamsFree(params, nparams); + params = NULL; + nparams = 0; + maxparams = 0; + + /* get users with domain */ + if (qemuAgentGetUsers(qemuMonitorTestGetAgent(test), + ¶ms, &nparams, &maxparams) < 0) + goto cleanup; + + if (virTypedParamsGetUInt(params, nparams, "user.count", &count) < 0) + goto cleanup; + if (count != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Expected '1' user, got '%u'", count); + goto cleanup; + } + + if (checkUserInfo(params, nparams, 0, "test", "DOMAIN", 1561739203584) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virTypedParamsFree(params, nparams); + qemuMonitorTestFree(test); + return ret; +} + + static int mymain(void) { @@ -931,6 +1078,7 @@ mymain(void) DO_TEST(CPU); DO_TEST(ArbitraryCommand); DO_TEST(GetInterfaces); + DO_TEST(Users); DO_TEST(Timeout); /* Timeout should always be called last */