char * virSystemdGetMachineNameByPID(pid_t pid) { DBusConnection *conn; DBusMessage *reply = NULL; char *name = NULL, *object = NULL; if (virSystemdHasMachined() < 0) goto cleanup; if (!(conn = virDBusGetSystemBus())) goto cleanup; if (virDBusCallMethod(conn, &reply, NULL, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "GetMachineByPID", "u", pid) < 0) goto cleanup; if (virDBusMessageDecode(reply, "o", &object) < 0) goto cleanup; virDBusMessageUnref(reply); reply = NULL; VIR_DEBUG("Domain with pid %lld has object path '%s'", (long long) pid, object); if (virDBusCallMethod(conn, &reply, NULL, "org.freedesktop.machine1", object, "org.freedesktop.DBus.Properties", "Get", "ss", "org.freedesktop.machine1.Machine", "Name") < 0) goto cleanup; if (virDBusMessageDecode(reply, "v", "s", &name) < 0) goto cleanup; VIR_DEBUG("Domain with pid %lld has machine name '%s'", (long long) pid, name); cleanup: VIR_FREE(object); virDBusMessageUnref(reply); return name; }
static int virSystemdPMSupportTarget(const char *methodName, bool *result) { int ret; DBusConnection *conn; DBusMessage *message = NULL; char *response; ret = virDBusIsServiceEnabled("org.freedesktop.login1"); if (ret < 0) return ret; if ((ret = virDBusIsServiceRegistered("org.freedesktop.login1")) < 0) return ret; if (!(conn = virDBusGetSystemBus())) return -1; ret = -1; if (virDBusCallMethod(conn, &message, NULL, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", methodName, NULL) < 0) return ret; if ((ret = virDBusMessageRead(message, "s", &response)) < 0) goto cleanup; *result = STREQ("yes", response) || STREQ("challenge", response); ret = 0; cleanup: virDBusMessageUnref(message); VIR_FREE(response); return ret; }
VIR_MOCK_WRAP_RET_ARGS(dbus_connection_send_with_reply_and_block, DBusMessage *, DBusConnection *, connection, DBusMessage *, message, int, timeout_milliseconds, DBusError *, error) { DBusMessage *reply = NULL; const char *service = dbus_message_get_destination(message); const char *member = dbus_message_get_member(message); VIR_MOCK_REAL_INIT(dbus_connection_send_with_reply_and_block); if (STREQ(service, "org.freedesktop.PolicyKit1") && STREQ(member, "CheckAuthorization")) { char *type; char *pidkey; unsigned int pidval; char *timekey; unsigned long long timeval; char *uidkey; int uidval; char *actionid; char **details; size_t detailslen; int allowInteraction; char *cancellationId; const char **retdetails = NULL; size_t retdetailslen = 0; const char *retdetailscancelled[] = { "polkit.dismissed", "true", }; int is_authorized = 1; int is_challenge = 0; if (virDBusMessageRead(message, "(sa{sv})sa&{ss}us", &type, 3, &pidkey, "u", &pidval, &timekey, "t", &timeval, &uidkey, "i", &uidval, &actionid, &detailslen, &details, &allowInteraction, &cancellationId) < 0) goto error; if (STREQ(actionid, "org.libvirt.test.success")) { is_authorized = 1; is_challenge = 0; } else if (STREQ(actionid, "org.libvirt.test.challenge")) { is_authorized = 0; is_challenge = 1; } else if (STREQ(actionid, "org.libvirt.test.cancelled")) { is_authorized = 0; is_challenge = 0; retdetails = retdetailscancelled; retdetailslen = ARRAY_CARDINALITY(retdetailscancelled) / 2; } else if (STREQ(actionid, "org.libvirt.test.details")) { size_t i; is_authorized = 0; is_challenge = 0; for (i = 0; i < detailslen / 2; i++) { if (STREQ(details[i * 2], "org.libvirt.test.person") && STREQ(details[(i * 2) + 1], "Fred")) { is_authorized = 1; is_challenge = 0; } } } else { is_authorized = 0; is_challenge = 0; } VIR_FREE(type); VIR_FREE(pidkey); VIR_FREE(timekey); VIR_FREE(uidkey); VIR_FREE(actionid); VIR_FREE(cancellationId); virStringListFreeCount(details, detailslen); if (virDBusCreateReply(&reply, "(bba&{ss})", is_authorized, is_challenge, retdetailslen, retdetails) < 0) goto error; } else { reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); } return reply; error: virDBusMessageUnref(reply); return NULL; }
VIR_MOCK_WRAP_RET_ARGS(dbus_connection_send_with_reply_and_block, DBusMessage *, DBusConnection *, connection, DBusMessage *, message, int, timeout_milliseconds, DBusError *, error) { DBusMessage *reply = NULL; const char *service = dbus_message_get_destination(message); const char *member = dbus_message_get_member(message); size_t i; size_t nargs = 0; char **args = NULL; char *type = NULL; VIR_MOCK_REAL_INIT(dbus_connection_send_with_reply_and_block); if (STREQ(service, "org.freedesktop.DBus") && STREQ(member, "ListNames")) { const char *svc1 = "org.foo.bar.wizz"; const char *svc2 = VIR_FIREWALL_FIREWALLD_SERVICE; DBusMessageIter iter; DBusMessageIter sub; reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub); if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &svc1)) goto error; if (!fwDisabled && !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &svc2)) goto error; dbus_message_iter_close_container(&iter, &sub); } else if (STREQ(service, VIR_FIREWALL_FIREWALLD_SERVICE) && STREQ(member, "passthrough")) { bool isAdd = false; bool doError = false; if (virDBusMessageDecode(message, "sa&s", &type, &nargs, &args) < 0) goto error; for (i = 0; i < nargs; i++) { /* Fake failure on the command with this IP addr */ if (STREQ(args[i], "-A")) { isAdd = true; } else if (isAdd && STREQ(args[i], "192.168.122.255")) { doError = true; } } if (fwBuf) { if (STREQ(type, "ipv4")) virBufferAddLit(fwBuf, IPTABLES_PATH); else if (STREQ(type, "ipv4")) virBufferAddLit(fwBuf, IP6TABLES_PATH); else virBufferAddLit(fwBuf, EBTABLES_PATH); } for (i = 0; i < nargs; i++) { if (fwBuf) { virBufferAddLit(fwBuf, " "); virBufferEscapeShell(fwBuf, args[i]); } } if (fwBuf) virBufferAddLit(fwBuf, "\n"); if (doError) { dbus_set_error_const(error, "org.firewalld.error", "something bad happened"); } else { if (nargs == 1 && STREQ(type, "ipv4") && STREQ(args[0], "-L")) { if (virDBusCreateReply(&reply, "s", TEST_FILTER_TABLE_LIST) < 0) goto error; } else if (nargs == 3 && STREQ(type, "ipv4") && STREQ(args[0], "-t") && STREQ(args[1], "nat") && STREQ(args[2], "-L")) { if (virDBusCreateReply(&reply, "s", TEST_NAT_TABLE_LIST) < 0) goto error; } else { if (virDBusCreateReply(&reply, "s", "success") < 0) goto error; } } } else { reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); } cleanup: VIR_FREE(type); for (i = 0; i < nargs; i++) VIR_FREE(args[i]); VIR_FREE(args); return reply; error: virDBusMessageUnref(reply); reply = NULL; if (error && !dbus_error_is_set(error)) dbus_set_error_const(error, "org.firewalld.error", "something unexpected happened"); goto cleanup; }
void virSystemdNotifyStartup(void) { #ifdef HAVE_SYS_UN_H const char *path; const char *msg = "READY=1"; int fd; struct sockaddr_un un = { .sun_family = AF_UNIX, }; struct iovec iov = { .iov_base = (char *)msg, .iov_len = strlen(msg), }; struct msghdr mh = { .msg_name = &un, .msg_iov = &iov, .msg_iovlen = 1, }; if (!(path = virGetEnvBlockSUID("NOTIFY_SOCKET"))) { VIR_DEBUG("Skipping systemd notify, not requested"); return; } /* NB sun_path field is *not* NUL-terminated, hence >, not >= */ if (strlen(path) > sizeof(un.sun_path)) { VIR_WARN("Systemd notify socket path '%s' too long", path); return; } memcpy(un.sun_path, path, strlen(path)); if (un.sun_path[0] == '@') un.sun_path[0] = '\0'; mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(path); fd = socket(AF_UNIX, SOCK_DGRAM, 0); if (fd < 0) { VIR_WARN("Unable to create socket FD"); return; } if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0) VIR_WARN("Failed to notify systemd"); VIR_FORCE_CLOSE(fd); #endif /* HAVE_SYS_UN_H */ } static int virSystemdPMSupportTarget(const char *methodName, bool *result) { int ret; DBusConnection *conn; DBusMessage *message = NULL; char *response; ret = virDBusIsServiceEnabled("org.freedesktop.login1"); if (ret < 0) return ret; if ((ret = virDBusIsServiceRegistered("org.freedesktop.login1")) < 0) return ret; if (!(conn = virDBusGetSystemBus())) return -1; ret = -1; if (virDBusCallMethod(conn, &message, NULL, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", methodName, NULL) < 0) return ret; if ((ret = virDBusMessageDecode(message, "s", &response)) < 0) goto cleanup; *result = STREQ("yes", response) || STREQ("challenge", response); ret = 0; cleanup: virDBusMessageUnref(message); VIR_FREE(response); return ret; } int virSystemdCanSuspend(bool *result) { return virSystemdPMSupportTarget("CanSuspend", result); } int virSystemdCanHibernate(bool *result) { return virSystemdPMSupportTarget("CanHibernate", result); } int virSystemdCanHybridSleep(bool *result) { return virSystemdPMSupportTarget("CanHybridSleep", result); }
/* * virPolkitCheckAuth: * @actionid: permission to check * @pid: client process ID * @startTime: process start time, or 0 * @uid: client process user ID * @details: NULL terminated (key, value) pair list * @allowInteraction: true if auth prompts are allowed * * Check if a client is authenticated with polkit * * Returns 0 on success, -1 on failure, -2 on auth denied */ int virPolkitCheckAuth(const char *actionid, pid_t pid, unsigned long long startTime, uid_t uid, const char **details, bool allowInteraction) { DBusConnection *sysbus; DBusMessage *reply = NULL; char **retdetails = NULL; size_t nretdetails = 0; bool is_authorized; bool is_challenge; bool is_dismissed = false; size_t i; int ret = -1; if (!(sysbus = virDBusGetSystemBus())) goto cleanup; VIR_INFO("Checking PID %lld running as %d", (long long) pid, uid); if (virDBusCallMethod(sysbus, &reply, NULL, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority", "CheckAuthorization", "(sa{sv})sa&{ss}us", "unix-process", 3, "pid", "u", (unsigned int)pid, "start-time", "t", startTime, "uid", "i", (int)uid, actionid, virStringListLength(details) / 2, details, allowInteraction, "" /* cancellation ID */) < 0) goto cleanup; if (virDBusMessageRead(reply, "(bba&{ss})", &is_authorized, &is_challenge, &nretdetails, &retdetails) < 0) goto cleanup; for (i = 0; i < (nretdetails / 2); i++) { if (STREQ(retdetails[(i * 2)], "polkit.dismissed") && STREQ(retdetails[(i * 2) + 1], "true")) is_dismissed = true; } VIR_DEBUG("is auth %d is challenge %d", is_authorized, is_challenge); if (is_authorized) { ret = 0; } else { ret = -2; if (is_dismissed) virReportError(VIR_ERR_AUTH_CANCELLED, "%s", _("user cancelled authentication process")); else if (is_challenge) virReportError(VIR_ERR_AUTH_UNAVAILABLE, _("no polkit agent available to authenticate " "action '%s'"), actionid); else virReportError(VIR_ERR_AUTH_FAILED, "%s", _("access denied by policy")); } cleanup: virStringListFreeCount(retdetails, nretdetails); virDBusMessageUnref(reply); return ret; }
VIR_MOCK_WRAP_RET_ARGS(dbus_connection_send_with_reply_and_block, DBusMessage *, DBusConnection *, connection, DBusMessage *, message, int, timeout_milliseconds, DBusError *, error) { DBusMessage *reply = NULL; const char *service = dbus_message_get_destination(message); const char *member = dbus_message_get_member(message); VIR_MOCK_REAL_INIT(dbus_connection_send_with_reply_and_block); if (STREQ(service, "org.freedesktop.machine1")) { if (getenv("FAIL_BAD_SERVICE")) { dbus_set_error_const(error, "org.freedesktop.systemd.badthing", "Something went wrong creating the machine"); } else { reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); if (STREQ(member, "GetMachineByPID")) { const char *object_path = "/org/freedesktop/machine1/machine/qemu_2ddemo"; DBusMessageIter iter; dbus_message_iter_init_append(reply, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &object_path)) goto error; } else if (STREQ(member, "Get")) { const char *name = "qemu-demo"; DBusMessageIter iter; DBusMessageIter sub; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "s", &sub); if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &name)) goto error; dbus_message_iter_close_container(&iter, &sub); } } } else if (STREQ(service, "org.freedesktop.login1")) { char *supported = getenv("RESULT_SUPPORT"); DBusMessageIter iter; reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); dbus_message_iter_init_append(reply, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &supported)) goto error; } else if (STREQ(service, "org.freedesktop.DBus") && STREQ(member, "ListActivatableNames")) { const char *svc1 = "org.foo.bar.wizz"; const char *svc2 = "org.freedesktop.machine1"; const char *svc3 = "org.freedesktop.login1"; DBusMessageIter iter; DBusMessageIter sub; reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub); if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &svc1)) goto error; if (!getenv("FAIL_NO_SERVICE") && !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &svc2)) goto error; if (!getenv("FAIL_NO_SERVICE") && !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &svc3)) goto error; dbus_message_iter_close_container(&iter, &sub); } else if (STREQ(service, "org.freedesktop.DBus") && STREQ(member, "ListNames")) { const char *svc1 = "org.foo.bar.wizz"; const char *svc2 = "org.freedesktop.systemd1"; const char *svc3 = "org.freedesktop.login1"; DBusMessageIter iter; DBusMessageIter sub; reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub); if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &svc1)) goto error; if ((!getenv("FAIL_NO_SERVICE") && !getenv("FAIL_NOT_REGISTERED")) && !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &svc2)) goto error; if ((!getenv("FAIL_NO_SERVICE") && !getenv("FAIL_NOT_REGISTERED")) && !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &svc3)) goto error; dbus_message_iter_close_container(&iter, &sub); } else { reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); } return reply; error: virDBusMessageUnref(reply); return NULL; }