diff --git a/configure.ac b/configure.ac index 69a01aeb8c..553015acdb 100644 --- a/configure.ac +++ b/configure.ac @@ -1257,6 +1257,14 @@ if test "x$with_polkit" = "xyes" || test "x$with_polkit" = "xcheck"; then AC_PATH_PROG([PKCHECK_PATH],[pkcheck], [], [/usr/sbin:$PATH]) if test "x$PKCHECK_PATH" != "x" ; then AC_DEFINE_UNQUOTED([PKCHECK_PATH],["$PKCHECK_PATH"],[Location of pkcheck program]) + AC_MSG_CHECKING([whether pkcheck supports uid value]) + pkcheck_supports_uid=`$PKG_CONFIG --variable pkcheck_supports_uid polkit-gobject-1` + if test "x$pkcheck_supports_uid" = "xtrue"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED([PKCHECK_SUPPORTS_UID], 1, [Pass uid to pkcheck]) + else + AC_MSG_RESULT([no]) + fi AC_DEFINE_UNQUOTED([WITH_POLKIT], 1, [use PolicyKit for UNIX socket access checks]) AC_DEFINE_UNQUOTED([WITH_POLKIT1], 1, diff --git a/daemon/remote.c b/daemon/remote.c index 2aff7c173c..6b082cf1f6 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2738,10 +2738,12 @@ remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED, int status = -1; char *ident = NULL; bool authdismissed = 0; + bool supportsuid = false; char *pkout = NULL; struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); virCommandPtr cmd = NULL; + static bool polkitInsecureWarned; virMutexLock(&priv->lock); action = virNetServerClientGetReadonly(client) ? @@ -2763,14 +2765,28 @@ remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED, goto authfail; } + if (timestamp == 0) { + VIR_WARN("Failing polkit auth due to missing client (pid=%lld) start time", + (long long)callerPid); + goto authfail; + } + VIR_INFO("Checking PID %lld running as %d", (long long) callerPid, callerUid); virCommandAddArg(cmd, "--process"); - if (timestamp != 0) { - virCommandAddArgFormat(cmd, "%lld,%llu", (long long) callerPid, timestamp); +# ifdef PKCHECK_SUPPORTS_UID + supportsuid = true; +# endif + if (supportsuid) { + virCommandAddArgFormat(cmd, "%lld,%llu,%lu", + (long long) callerPid, timestamp, (unsigned long) callerUid); } else { - virCommandAddArgFormat(cmd, "%lld", (long long) callerPid); + if (!polkitInsecureWarned) { + VIR_WARN("No support for caller UID with pkcheck. This deployment is known to be insecure."); + polkitInsecureWarned = true; + } + virCommandAddArgFormat(cmd, "%lld,%llu", (long long) callerPid, timestamp); } virCommandAddArg(cmd, "--allow-user-interaction"); diff --git a/libvirt.spec.in b/libvirt.spec.in index a55e87c0a5..f89914953d 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -509,8 +509,7 @@ BuildRequires: cyrus-sasl-devel %endif %if %{with_polkit} %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6 -# Only need the binary, not -devel -BuildRequires: polkit >= 0.93 +BuildRequires: polkit-devel >= 0.93 %else BuildRequires: PolicyKit-devel >= 0.6 %endif diff --git a/src/access/viraccessdriverpolkit.c b/src/access/viraccessdriverpolkit.c index b472bc3020..ff8258306a 100644 --- a/src/access/viraccessdriverpolkit.c +++ b/src/access/viraccessdriverpolkit.c @@ -72,8 +72,12 @@ static char * virAccessDriverPolkitFormatProcess(const char *actionid) { virIdentityPtr identity = virIdentityGetCurrent(); - const char *process = NULL; + const char *callerPid = NULL; + const char *callerTime = NULL; + const char *callerUid = NULL; char *ret = NULL; + bool supportsuid = false; + static bool polkitInsecureWarned; if (!identity) { virAccessError(VIR_ERR_ACCESS_DENIED, @@ -81,17 +85,43 @@ virAccessDriverPolkitFormatProcess(const char *actionid) actionid); return NULL; } - if (virIdentityGetAttr(identity, VIR_IDENTITY_ATTR_UNIX_PROCESS_ID, &process) < 0) + if (virIdentityGetAttr(identity, VIR_IDENTITY_ATTR_UNIX_PROCESS_ID, &callerPid) < 0) + goto cleanup; + if (virIdentityGetAttr(identity, VIR_IDENTITY_ATTR_UNIX_PROCESS_TIME, &callerTime) < 0) + goto cleanup; + if (virIdentityGetAttr(identity, VIR_IDENTITY_ATTR_UNIX_USER_ID, &callerUid) < 0) goto cleanup; - if (!process) { + if (!callerPid) { virAccessError(VIR_ERR_INTERNAL_ERROR, "%s", _("No UNIX process ID available")); goto cleanup; } - - if (VIR_STRDUP(ret, process) < 0) + if (!callerTime) { + virAccessError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No UNIX process start time available")); goto cleanup; + } + if (!callerUid) { + virAccessError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No UNIX caller UID available")); + goto cleanup; + } + +#ifdef PKCHECK_SUPPORTS_UID + supportsuid = true; +#endif + if (supportsuid) { + if (virAsprintf(&ret, "%s,%s,%s", callerPid, callerTime, callerUid) < 0) + goto cleanup; + } else { + if (!polkitInsecureWarned) { + VIR_WARN("No support for caller UID with pkcheck. This deployment is known to be insecure."); + polkitInsecureWarned = true; + } + if (virAsprintf(&ret, "%s,%s", callerPid, callerTime) < 0) + goto cleanup; + } cleanup: virObjectUnref(identity);