/* virPolkitAgentCreate: * * Allocate and setup a polkit agent * * Returns a virCommandPtr on success and NULL on failure */ virPolkitAgentPtr virPolkitAgentCreate(void) { virPolkitAgentPtr agent = NULL; int pipe_fd[2] = {-1, -1}; struct pollfd pollfd; int outfd = STDOUT_FILENO; int errfd = STDERR_FILENO; if (!isatty(STDIN_FILENO)) goto error; if (pipe2(pipe_fd, 0) < 0) goto error; if (VIR_ALLOC(agent) < 0) goto error; agent->cmd = virCommandNewArgList(PKTTYAGENT, "--process", NULL); virCommandAddArgFormat(agent->cmd, "%lld", (long long int) getpid()); virCommandAddArg(agent->cmd, "--notify-fd"); virCommandAddArgFormat(agent->cmd, "%d", pipe_fd[1]); virCommandAddArg(agent->cmd, "--fallback"); virCommandSetInputFD(agent->cmd, STDIN_FILENO); virCommandSetOutputFD(agent->cmd, &outfd); virCommandSetErrorFD(agent->cmd, &errfd); virCommandPassFD(agent->cmd, pipe_fd[1], VIR_COMMAND_PASS_FD_CLOSE_PARENT); if (virCommandRunAsync(agent->cmd, NULL) < 0) goto error; pollfd.fd = pipe_fd[0]; pollfd.events = POLLHUP; if (poll(&pollfd, 1, -1) < 0) goto error; return agent; error: VIR_FORCE_CLOSE(pipe_fd[0]); VIR_FORCE_CLOSE(pipe_fd[1]); virPolkitAgentDestroy(agent); return NULL; }
/* Main Function which should be used for connecting. * This function properly handles keepalive settings. */ virConnectPtr virshConnect(vshControl *ctl, const char *uri, bool readonly) { virConnectPtr c = NULL; int interval = 5; /* Default */ int count = 6; /* Default */ bool keepalive_forced = false; virPolkitAgentPtr pkagent = NULL; int authfail = 0; bool agentCreated = false; if (ctl->keepalive_interval >= 0) { interval = ctl->keepalive_interval; keepalive_forced = true; } if (ctl->keepalive_count >= 0) { count = ctl->keepalive_count; keepalive_forced = true; } do { virErrorPtr err; if ((c = virConnectOpenAuth(uri, virConnectAuthPtrDefault, readonly ? VIR_CONNECT_RO : 0))) break; if (readonly) goto cleanup; err = virGetLastError(); if (!agentCreated && err && err->domain == VIR_FROM_POLKIT && err->code == VIR_ERR_AUTH_UNAVAILABLE) { if (!pkagent && !(pkagent = virPolkitAgentCreate())) goto cleanup; agentCreated = true; } 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) goto cleanup; if (interval > 0 && virConnectSetKeepAlive(c, interval, count) != 0) { if (keepalive_forced) { vshError(ctl, "%s", _("Cannot setup keepalive on connection " "as requested, disconnecting")); virConnectClose(c); c = NULL; goto cleanup; } vshDebug(ctl, VSH_ERR_INFO, "%s", _("Failed to setup keepalive on connection\n")); } cleanup: virPolkitAgentDestroy(pkagent); return c; }