virsh: Add support for text based polkit authentication

https://bugzilla.redhat.com/show_bug.cgi?id=872166

When the login session doesn't have an ssh -X type display agent in
order for libvirtd to run the polkit session authentication, attempts
to run 'virsh -c qemu:///system list' from an unauthorized user (or one
that isn't part of the libvirt /etc/group) will fail with the following
error from libvirtd:

error: authentication unavailable: no polkit agent available to
       authenticate action 'org.libvirt.unix.manage'

In order to handle the local authentication, we will use the new
virPolkitAgentCreate API in order to create a text based authentication
agent for our non readonly session to authenticate with.

The new code will execute in a loop allowing 5 failures to authenticate
before failing out.

With this patch in place, the following occurs:

$ virsh -c qemu:///system list
==== AUTHENTICATING FOR org.libvirt.unix.manage ===
System policy prevents management of local virtualized systems
Authenticating as: Some User (SUser)
Password:
==== AUTHENTICATION COMPLETE ===
 Id    Name                           State
 ----------------------------------------------------
  1     somedomain                     running

$
This commit is contained in:
John Ferlan 2016-02-09 14:08:42 -05:00
parent 6fb96a7f8b
commit ea48397b01
2 changed files with 35 additions and 4 deletions

View File

@ -143,6 +143,8 @@ virshConnect(vshControl *ctl, const char *uri, bool readonly)
int interval = 5; /* Default */ int interval = 5; /* Default */
int count = 6; /* Default */ int count = 6; /* Default */
bool keepalive_forced = false; bool keepalive_forced = false;
virPolkitAgentPtr pkagent = NULL;
int authfail = 0;
if (ctl->keepalive_interval >= 0) { if (ctl->keepalive_interval >= 0) {
interval = ctl->keepalive_interval; interval = ctl->keepalive_interval;
@ -153,10 +155,35 @@ virshConnect(vshControl *ctl, const char *uri, bool readonly)
keepalive_forced = true; keepalive_forced = true;
} }
c = virConnectOpenAuth(uri, virConnectAuthPtrDefault, do {
readonly ? VIR_CONNECT_RO : 0); virErrorPtr err;
if ((c = virConnectOpenAuth(uri, virConnectAuthPtrDefault,
readonly ? VIR_CONNECT_RO : 0)))
break;
if (readonly)
goto cleanup;
err = virGetLastError();
if (err && err->domain == VIR_FROM_POLKIT &&
err->code == VIR_ERR_AUTH_UNAVAILABLE) {
if (!(pkagent = virPolkitAgentCreate()))
goto cleanup;
} else if (err && err->domain == VIR_FROM_POLKIT &&
err->code == VIR_ERR_AUTH_FAILED) {
authfail++;
} else {
goto cleanup;
}
virResetLastError();
/* Failure to authenticate 5 times should be enough.
* No sense prolonging the agony.
*/
} while (authfail < 5);
if (!c) if (!c)
return NULL; goto cleanup;
if (interval > 0 && if (interval > 0 &&
virConnectSetKeepAlive(c, interval, count) != 0) { virConnectSetKeepAlive(c, interval, count) != 0) {
@ -165,12 +192,15 @@ virshConnect(vshControl *ctl, const char *uri, bool readonly)
_("Cannot setup keepalive on connection " _("Cannot setup keepalive on connection "
"as requested, disconnecting")); "as requested, disconnecting"));
virConnectClose(c); virConnectClose(c);
return NULL; c = NULL;
goto cleanup;
} }
vshDebug(ctl, VSH_ERR_INFO, "%s", vshDebug(ctl, VSH_ERR_INFO, "%s",
_("Failed to setup keepalive on connection\n")); _("Failed to setup keepalive on connection\n"));
} }
cleanup:
virPolkitAgentDestroy(pkagent);
return c; return c;
} }

View File

@ -36,6 +36,7 @@
# include "internal.h" # include "internal.h"
# include "virerror.h" # include "virerror.h"
# include "virthread.h" # include "virthread.h"
# include "virpolkit.h"
# include "vsh.h" # include "vsh.h"
# define VIRSH_PROMPT_RW "virsh # " # define VIRSH_PROMPT_RW "virsh # "