2010-03-14 19:50:14 +00:00
|
|
|
/*
|
2012-03-19 16:21:12 +00:00
|
|
|
* virauth.c: authentication related utility functions
|
2010-03-14 19:50:14 +00:00
|
|
|
*
|
2012-07-24 14:08:46 +00:00
|
|
|
* Copyright (C) 2012 Red Hat, Inc.
|
2010-03-14 19:50:14 +00:00
|
|
|
* Copyright (C) 2010 Matthias Bolte <matthias.bolte@googlemail.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-03-14 19:50:14 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2012-03-20 15:40:05 +00:00
|
|
|
|
2012-03-19 16:21:12 +00:00
|
|
|
#include "virauth.h"
|
2019-04-01 14:28:05 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-03-20 15:40:05 +00:00
|
|
|
#include "datatypes.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-03-20 15:40:05 +00:00
|
|
|
#include "configmake.h"
|
2012-03-20 11:11:10 +00:00
|
|
|
#include "virauthconfig.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2012-03-20 15:40:05 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_AUTH
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.auth");
|
|
|
|
|
2013-07-09 14:14:45 +00:00
|
|
|
int
|
|
|
|
virAuthGetConfigFilePathURI(virURIPtr uri,
|
|
|
|
char **path)
|
2012-03-20 15:40:05 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
2019-08-01 12:35:56 +00:00
|
|
|
const char *authenv = getenv("LIBVIRT_AUTH_FILE");
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *userdir = NULL;
|
2012-03-20 15:40:05 +00:00
|
|
|
|
|
|
|
*path = NULL;
|
|
|
|
|
|
|
|
VIR_DEBUG("Determining auth config file path");
|
|
|
|
|
|
|
|
if (authenv) {
|
|
|
|
VIR_DEBUG("Using path from env '%s'", authenv);
|
2019-10-20 11:49:46 +00:00
|
|
|
*path = g_strdup(authenv);
|
2012-03-20 15:40:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-09 14:14:45 +00:00
|
|
|
if (uri) {
|
|
|
|
for (i = 0; i < uri->paramsCount; i++) {
|
|
|
|
if (STREQ_NULLABLE(uri->params[i].name, "authfile") &&
|
|
|
|
uri->params[i].value) {
|
|
|
|
VIR_DEBUG("Using path from URI '%s'", uri->params[i].value);
|
2019-10-20 11:49:46 +00:00
|
|
|
*path = g_strdup(uri->params[i].value);
|
2012-07-24 14:08:46 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-03-20 15:40:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-19 08:33:54 +00:00
|
|
|
userdir = virGetUserConfigDirectory();
|
2012-03-20 15:40:05 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
*path = g_strdup_printf("%s/auth.conf", userdir);
|
2012-03-20 15:40:05 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Checking for readability of '%s'", *path);
|
|
|
|
if (access(*path, R_OK) == 0)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
VIR_FREE(*path);
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
*path = g_strdup(SYSCONFDIR "/libvirt/auth.conf");
|
2012-03-20 15:40:05 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Checking for readability of '%s'", *path);
|
|
|
|
if (access(*path, R_OK) == 0)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
VIR_FREE(*path);
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
done:
|
2012-03-20 15:40:05 +00:00
|
|
|
VIR_DEBUG("Using auth file '%s'", NULLSTR(*path));
|
|
|
|
|
2018-07-13 17:54:54 +00:00
|
|
|
return 0;
|
2012-03-20 15:40:05 +00:00
|
|
|
}
|
2010-03-14 19:50:14 +00:00
|
|
|
|
|
|
|
|
2013-07-09 14:14:45 +00:00
|
|
|
int
|
|
|
|
virAuthGetConfigFilePath(virConnectPtr conn,
|
|
|
|
char **path)
|
|
|
|
{
|
|
|
|
return virAuthGetConfigFilePathURI(conn ? conn->uri : NULL, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-20 11:11:10 +00:00
|
|
|
static int
|
2013-07-09 14:14:45 +00:00
|
|
|
virAuthGetCredential(const char *servicename,
|
|
|
|
const char *hostname,
|
2012-03-20 11:11:10 +00:00
|
|
|
const char *credname,
|
2013-07-09 14:14:45 +00:00
|
|
|
const char *path,
|
2012-03-20 11:11:10 +00:00
|
|
|
char **value)
|
|
|
|
{
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(virAuthConfig) config = NULL;
|
2012-03-20 11:11:10 +00:00
|
|
|
|
|
|
|
*value = NULL;
|
|
|
|
|
2013-07-09 14:14:45 +00:00
|
|
|
if (path == NULL)
|
|
|
|
return 0;
|
2012-03-20 11:11:10 +00:00
|
|
|
|
|
|
|
if (!(config = virAuthConfigNew(path)))
|
2018-07-13 17:54:55 +00:00
|
|
|
return -1;
|
2012-03-20 11:11:10 +00:00
|
|
|
|
|
|
|
if (virAuthConfigLookup(config,
|
|
|
|
servicename,
|
2013-07-09 14:14:45 +00:00
|
|
|
hostname,
|
2012-03-20 11:11:10 +00:00
|
|
|
credname,
|
2020-06-16 12:07:02 +00:00
|
|
|
value) < 0)
|
2018-07-13 17:54:55 +00:00
|
|
|
return -1;
|
2012-03-20 11:11:10 +00:00
|
|
|
|
2018-07-13 17:54:55 +00:00
|
|
|
return 0;
|
2012-03-20 11:11:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-14 19:50:14 +00:00
|
|
|
char *
|
2013-07-09 14:14:45 +00:00
|
|
|
virAuthGetUsernamePath(const char *path,
|
|
|
|
virConnectAuthPtr auth,
|
|
|
|
const char *servicename,
|
|
|
|
const char *defaultUsername,
|
|
|
|
const char *hostname)
|
2010-03-14 19:50:14 +00:00
|
|
|
{
|
|
|
|
unsigned int ncred;
|
|
|
|
virConnectCredential cred;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *prompt = NULL;
|
2012-03-20 11:11:10 +00:00
|
|
|
char *ret = NULL;
|
|
|
|
|
2013-07-09 14:14:45 +00:00
|
|
|
if (virAuthGetCredential(servicename, hostname, "username", path, &ret) < 0)
|
2012-03-20 11:11:10 +00:00
|
|
|
return NULL;
|
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
2010-03-14 19:50:14 +00:00
|
|
|
|
2018-08-14 14:03:10 +00:00
|
|
|
if (!auth) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Missing authentication credentials"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-29 09:52:04 +00:00
|
|
|
memset(&cred, 0, sizeof(virConnectCredential));
|
2010-03-14 19:50:14 +00:00
|
|
|
|
|
|
|
if (defaultUsername != NULL) {
|
2019-10-22 13:26:14 +00:00
|
|
|
prompt = g_strdup_printf(_("Enter username for %s [%s]"), hostname,
|
|
|
|
defaultUsername);
|
2010-03-14 19:50:14 +00:00
|
|
|
} else {
|
2019-10-22 13:26:14 +00:00
|
|
|
prompt = g_strdup_printf(_("Enter username for %s"), hostname);
|
2010-03-14 19:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (ncred = 0; ncred < auth->ncredtype; ncred++) {
|
2014-11-13 14:28:18 +00:00
|
|
|
if (auth->credtype[ncred] != VIR_CRED_AUTHNAME)
|
2010-03-14 19:50:14 +00:00
|
|
|
continue;
|
|
|
|
|
2018-08-14 14:05:33 +00:00
|
|
|
if (!auth->cb) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Missing authentication callback"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-14 19:50:14 +00:00
|
|
|
cred.type = VIR_CRED_AUTHNAME;
|
|
|
|
cred.prompt = prompt;
|
|
|
|
cred.challenge = hostname;
|
|
|
|
cred.defresult = defaultUsername;
|
|
|
|
cred.result = NULL;
|
|
|
|
cred.resultlen = 0;
|
|
|
|
|
2018-08-14 14:14:22 +00:00
|
|
|
if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) {
|
|
|
|
virReportError(VIR_ERR_AUTH_FAILED, "%s",
|
|
|
|
_("Username request failed"));
|
2010-03-14 19:50:14 +00:00
|
|
|
VIR_FREE(cred.result);
|
2018-08-14 14:14:22 +00:00
|
|
|
}
|
2010-03-14 19:50:14 +00:00
|
|
|
|
2018-08-14 14:11:50 +00:00
|
|
|
return cred.result;
|
2010-03-14 19:50:14 +00:00
|
|
|
}
|
|
|
|
|
2018-08-14 14:11:50 +00:00
|
|
|
virReportError(VIR_ERR_AUTH_FAILED, "%s",
|
|
|
|
_("Missing VIR_CRED_AUTHNAME credential type"));
|
|
|
|
return NULL;
|
2010-03-14 19:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2013-07-09 14:14:45 +00:00
|
|
|
virAuthGetUsername(virConnectPtr conn,
|
2012-03-20 11:11:10 +00:00
|
|
|
virConnectAuthPtr auth,
|
|
|
|
const char *servicename,
|
2013-07-09 14:14:45 +00:00
|
|
|
const char *defaultUsername,
|
2010-03-14 19:50:14 +00:00
|
|
|
const char *hostname)
|
2013-07-09 14:14:45 +00:00
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *path = NULL;
|
2013-07-09 14:14:45 +00:00
|
|
|
|
|
|
|
if (virAuthGetConfigFilePath(conn, &path) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2018-07-13 17:54:54 +00:00
|
|
|
return virAuthGetUsernamePath(path, auth, servicename,
|
2018-08-14 16:34:43 +00:00
|
|
|
defaultUsername, hostname);
|
2013-07-09 14:14:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
virAuthGetPasswordPath(const char *path,
|
|
|
|
virConnectAuthPtr auth,
|
|
|
|
const char *servicename,
|
|
|
|
const char *username,
|
|
|
|
const char *hostname)
|
2010-03-14 19:50:14 +00:00
|
|
|
{
|
|
|
|
unsigned int ncred;
|
|
|
|
virConnectCredential cred;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *prompt = NULL;
|
2012-03-20 11:11:10 +00:00
|
|
|
char *ret = NULL;
|
|
|
|
|
2013-07-09 14:14:45 +00:00
|
|
|
if (virAuthGetCredential(servicename, hostname, "password", path, &ret) < 0)
|
2012-03-20 11:11:10 +00:00
|
|
|
return NULL;
|
|
|
|
if (ret != NULL)
|
|
|
|
return ret;
|
2010-03-14 19:50:14 +00:00
|
|
|
|
2018-08-14 14:03:10 +00:00
|
|
|
if (!auth) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Missing authentication credentials"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-29 09:52:04 +00:00
|
|
|
memset(&cred, 0, sizeof(virConnectCredential));
|
2010-03-14 19:50:14 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
prompt = g_strdup_printf(_("Enter %s's password for %s"), username, hostname);
|
2010-03-14 19:50:14 +00:00
|
|
|
|
|
|
|
for (ncred = 0; ncred < auth->ncredtype; ncred++) {
|
|
|
|
if (auth->credtype[ncred] != VIR_CRED_PASSPHRASE &&
|
|
|
|
auth->credtype[ncred] != VIR_CRED_NOECHOPROMPT) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-08-14 14:05:33 +00:00
|
|
|
if (!auth->cb) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Missing authentication callback"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-14 19:50:14 +00:00
|
|
|
cred.type = auth->credtype[ncred];
|
|
|
|
cred.prompt = prompt;
|
|
|
|
cred.challenge = hostname;
|
|
|
|
cred.defresult = NULL;
|
|
|
|
cred.result = NULL;
|
|
|
|
cred.resultlen = 0;
|
|
|
|
|
2018-08-14 14:14:22 +00:00
|
|
|
if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) {
|
|
|
|
virReportError(VIR_ERR_AUTH_FAILED, "%s",
|
|
|
|
_("Password request failed"));
|
2010-03-14 19:50:14 +00:00
|
|
|
VIR_FREE(cred.result);
|
2018-08-14 14:14:22 +00:00
|
|
|
}
|
2010-03-14 19:50:14 +00:00
|
|
|
|
2018-08-14 14:11:50 +00:00
|
|
|
return cred.result;
|
2010-03-14 19:50:14 +00:00
|
|
|
}
|
|
|
|
|
2018-08-14 14:11:50 +00:00
|
|
|
virReportError(VIR_ERR_AUTH_FAILED, "%s",
|
|
|
|
_("Missing VIR_CRED_PASSPHRASE or VIR_CRED_NOECHOPROMPT "
|
|
|
|
"credential type"));
|
|
|
|
return NULL;
|
2010-03-14 19:50:14 +00:00
|
|
|
}
|
2013-07-09 14:14:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
virAuthGetPassword(virConnectPtr conn,
|
|
|
|
virConnectAuthPtr auth,
|
|
|
|
const char *servicename,
|
|
|
|
const char *username,
|
|
|
|
const char *hostname)
|
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *path = NULL;
|
2013-07-09 14:14:45 +00:00
|
|
|
|
|
|
|
if (virAuthGetConfigFilePath(conn, &path) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2018-07-13 17:54:54 +00:00
|
|
|
return virAuthGetPasswordPath(path, auth, servicename, username, hostname);
|
2013-07-09 14:14:45 +00:00
|
|
|
}
|