admin: Introduce virAdmClientGetInfo API

Expose a public API to retrieve some identity and connection information about
a client connected to the specified server on daemon. The identity info
retrieved is mostly connection transport dependent, i.e. there won't be any
socket address returned for a local (UNIX socket) connection, while on the
other hand, when connected through TLS or unencrypted TCP, obviously no UNIX
process identification will be present in the returned data. All supported
values that can be returned in typed params are exposed and documented in
include/libvirt/libvirt-admin.h

Signed-off-by: Erik Skultety <eskultet@redhat.com>
This commit is contained in:
Erik Skultety 2016-04-22 13:05:42 +02:00
parent 8420a53edf
commit 4a0e910825
10 changed files with 290 additions and 1 deletions

View File

@ -236,4 +236,63 @@ adminDispatchServerSetThreadpoolParameters(virNetServerPtr server ATTRIBUTE_UNUS
virObjectUnref(srv); virObjectUnref(srv);
return rv; return rv;
} }
static int
adminDispatchClientGetInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
struct admin_client_get_info_args *args,
struct admin_client_get_info_ret *ret)
{
int rv = -1;
virNetServerPtr srv = NULL;
virNetServerClientPtr clnt = NULL;
virTypedParameterPtr params = NULL;
int nparams = 0;
struct daemonAdmClientPrivate *priv =
virNetServerClientGetPrivateData(client);
if (!(srv = virNetDaemonGetServer(priv->dmn, args->clnt.srv.name))) {
virReportError(VIR_ERR_NO_SERVER,
_("no server with matching name '%s' found"),
args->clnt.srv.name);
goto cleanup;
}
if (!(clnt = virNetServerGetClient(srv, args->clnt.id))) {
virReportError(VIR_ERR_NO_CLIENT,
_("no client with matching id '%lu' found"),
args->clnt.id);
goto cleanup;
}
if (adminClientGetInfo(clnt, &params, &nparams, args->flags) < 0)
goto cleanup;
if (nparams > ADMIN_CLIENT_INFO_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Number of client info parameters %d exceeds max "
"allowed limit: %d"), nparams,
ADMIN_CLIENT_INFO_PARAMETERS_MAX);
goto cleanup;
}
if (virTypedParamsSerialize(params, nparams,
(virTypedParameterRemotePtr *) &ret->params.params_val,
&ret->params.params_len,
VIR_TYPED_PARAM_STRING_OKAY) < 0)
goto cleanup;
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virTypedParamsFree(params, nparams);
virObjectUnref(clnt);
virObjectUnref(srv);
return rv;
}
#include "admin_dispatch.h" #include "admin_dispatch.h"

View File

@ -27,6 +27,7 @@
#include "datatypes.h" #include "datatypes.h"
#include "viralloc.h" #include "viralloc.h"
#include "virerror.h" #include "virerror.h"
#include "viridentity.h"
#include "virlog.h" #include "virlog.h"
#include "virnetdaemon.h" #include "virnetdaemon.h"
#include "virnetserver.h" #include "virnetserver.h"
@ -211,3 +212,94 @@ adminServerLookupClient(virNetServerPtr srv,
return virNetServerGetClient(srv, id); return virNetServerGetClient(srv, id);
} }
int
adminClientGetInfo(virNetServerClientPtr client,
virTypedParameterPtr *params,
int *nparams,
unsigned int flags)
{
int ret = -1;
int maxparams = 0;
bool readonly;
const char *sock_addr = NULL;
const char *attr = NULL;
virTypedParameterPtr tmpparams = NULL;
virIdentityPtr identity = NULL;
virCheckFlags(0, -1);
if (virNetServerClientGetInfo(client, &readonly,
&sock_addr, &identity) < 0)
goto cleanup;
if (virTypedParamsAddBoolean(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_READONLY,
readonly) < 0)
goto cleanup;
if (!virNetServerClientIsLocal(client)) {
if (virTypedParamsAddString(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_SOCKET_ADDR,
sock_addr) < 0)
goto cleanup;
if (virIdentityGetSASLUserName(identity, &attr) < 0 ||
(attr &&
virTypedParamsAddString(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_SASL_USER_NAME,
attr) < 0))
goto cleanup;
if (virIdentityGetX509DName(identity, &attr) < 0 ||
(attr &&
virTypedParamsAddString(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_X509_DISTINGUISHED_NAME,
attr) < 0))
goto cleanup;
} else {
pid_t pid;
uid_t uid;
gid_t gid;
if (virIdentityGetUNIXUserID(identity, &uid) < 0 ||
virTypedParamsAddInt(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_UNIX_USER_ID, uid) < 0)
goto cleanup;
if (virIdentityGetUNIXUserName(identity, &attr) < 0 ||
virTypedParamsAddString(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_UNIX_USER_NAME,
attr) < 0)
goto cleanup;
if (virIdentityGetUNIXGroupID(identity, &gid) < 0 ||
virTypedParamsAddInt(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_UNIX_GROUP_ID, gid) < 0)
goto cleanup;
if (virIdentityGetUNIXGroupName(identity, &attr) < 0 ||
virTypedParamsAddString(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_UNIX_GROUP_NAME,
attr) < 0)
goto cleanup;
if (virIdentityGetUNIXProcessID(identity, &pid) < 0 ||
virTypedParamsAddInt(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_UNIX_PROCESS_ID, pid) < 0)
goto cleanup;
}
if (virIdentityGetSELinuxContext(identity, &attr) < 0 ||
(attr &&
virTypedParamsAddString(&tmpparams, nparams, &maxparams,
VIR_CLIENT_INFO_SELINUX_CONTEXT, attr) < 0))
goto cleanup;
*params = tmpparams;
tmpparams = NULL;
ret = 0;
cleanup:
virObjectUnref(identity);
return ret;
}

View File

@ -54,4 +54,9 @@ virNetServerClientPtr adminServerLookupClient(virNetServerPtr srv,
unsigned long long id, unsigned long long id,
unsigned int flags); unsigned int flags);
int adminClientGetInfo(virNetServerClientPtr client,
virTypedParameterPtr *params,
int *nparams,
unsigned int flags);
#endif /* __LIBVIRTD_ADMIN_SERVER_H__ */ #endif /* __LIBVIRTD_ADMIN_SERVER_H__ */

View File

@ -344,6 +344,11 @@ virAdmServerLookupClient(virAdmServerPtr srv,
# define VIR_CLIENT_INFO_SELINUX_CONTEXT "selinux_context" # define VIR_CLIENT_INFO_SELINUX_CONTEXT "selinux_context"
int virAdmClientGetInfo(virAdmClientPtr client,
virTypedParameterPtr *params,
int *nparams,
unsigned int flags);
# ifdef __cplusplus # ifdef __cplusplus
} }
# endif # endif

View File

@ -42,6 +42,9 @@ const ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX = 32;
/* Upper limit on list of clients */ /* Upper limit on list of clients */
const ADMIN_CLIENT_LIST_MAX = 16384; const ADMIN_CLIENT_LIST_MAX = 16384;
/* Upper limit on number of client info parameters */
const ADMIN_CLIENT_INFO_PARAMETERS_MAX = 64;
/* A long string, which may NOT be NULL. */ /* A long string, which may NOT be NULL. */
typedef string admin_nonnull_string<ADMIN_STRING_MAX>; typedef string admin_nonnull_string<ADMIN_STRING_MAX>;
@ -148,6 +151,15 @@ struct admin_server_lookup_client_ret {
admin_nonnull_client clnt; admin_nonnull_client clnt;
}; };
struct admin_client_get_info_args {
admin_nonnull_client clnt;
unsigned int flags;
};
struct admin_client_get_info_ret { /* insert@1 */
admin_typed_param params<ADMIN_CLIENT_INFO_PARAMETERS_MAX>;
};
/* Define the program number, protocol version and procedure numbers here. */ /* Define the program number, protocol version and procedure numbers here. */
const ADMIN_PROGRAM = 0x06900690; const ADMIN_PROGRAM = 0x06900690;
const ADMIN_PROTOCOL_VERSION = 1; const ADMIN_PROTOCOL_VERSION = 1;
@ -213,5 +225,10 @@ enum admin_procedure {
/** /**
* @generate: both * @generate: both
*/ */
ADMIN_PROC_SERVER_LOOKUP_CLIENT = 9 ADMIN_PROC_SERVER_LOOKUP_CLIENT = 9,
/**
* @generate: none
*/
ADMIN_PROC_CLIENT_GET_INFO = 10
}; };

View File

@ -67,6 +67,16 @@ make_nonnull_server(admin_nonnull_server *srv_dst, virAdmServerPtr srv_src)
srv_dst->name = srv_src->name; srv_dst->name = srv_src->name;
} }
static void
make_nonnull_client(admin_nonnull_client *client_dst,
virAdmClientPtr client_src)
{
client_dst->id = client_src->id;
client_dst->transport = client_src->transport;
client_dst->timestamp = client_src->timestamp;
make_nonnull_server(&client_dst->srv, client_src->srv);
}
static int static int
callFull(virAdmConnectPtr conn ATTRIBUTE_UNUSED, callFull(virAdmConnectPtr conn ATTRIBUTE_UNUSED,
remoteAdminPrivPtr priv, remoteAdminPrivPtr priv,
@ -308,3 +318,40 @@ remoteAdminServerSetThreadPoolParameters(virAdmServerPtr srv,
virObjectUnlock(priv); virObjectUnlock(priv);
return rv; return rv;
} }
static int
remoteAdminClientGetInfo(virAdmClientPtr client,
virTypedParameterPtr *params,
int *nparams,
unsigned int flags)
{
int rv = -1;
remoteAdminPrivPtr priv = client->srv->conn->privateData;
admin_client_get_info_args args;
admin_client_get_info_ret ret;
args.flags = flags;
make_nonnull_client(&args.clnt, client);
memset(&ret, 0, sizeof(ret));
virObjectLock(priv);
if (call(client->srv->conn, 0, ADMIN_PROC_CLIENT_GET_INFO,
(xdrproc_t)xdr_admin_client_get_info_args, (char *) &args,
(xdrproc_t)xdr_admin_client_get_info_ret, (char *) &ret) == -1)
goto cleanup;
if (virTypedParamsDeserialize((virTypedParameterRemotePtr) ret.params.params_val,
ret.params.params_len,
ADMIN_CLIENT_INFO_PARAMETERS_MAX,
params,
nparams) < 0)
goto cleanup;
rv = 0;
xdr_free((xdrproc_t)xdr_admin_client_get_info_ret, (char *) &ret);
cleanup:
virObjectUnlock(priv);
return rv;
}

View File

@ -95,6 +95,16 @@ struct admin_server_lookup_client_args {
struct admin_server_lookup_client_ret { struct admin_server_lookup_client_ret {
admin_nonnull_client clnt; admin_nonnull_client clnt;
}; };
struct admin_client_get_info_args {
admin_nonnull_client clnt;
u_int flags;
};
struct admin_client_get_info_ret {
struct {
u_int params_len;
admin_typed_param * params_val;
} params;
};
enum admin_procedure { enum admin_procedure {
ADMIN_PROC_CONNECT_OPEN = 1, ADMIN_PROC_CONNECT_OPEN = 1,
ADMIN_PROC_CONNECT_CLOSE = 2, ADMIN_PROC_CONNECT_CLOSE = 2,
@ -105,4 +115,5 @@ enum admin_procedure {
ADMIN_PROC_SERVER_SET_THREADPOOL_PARAMETERS = 7, ADMIN_PROC_SERVER_SET_THREADPOOL_PARAMETERS = 7,
ADMIN_PROC_SERVER_LIST_CLIENTS = 8, ADMIN_PROC_SERVER_LIST_CLIENTS = 8,
ADMIN_PROC_SERVER_LOOKUP_CLIENT = 9, ADMIN_PROC_SERVER_LOOKUP_CLIENT = 9,
ADMIN_PROC_CLIENT_GET_INFO = 10,
}; };

View File

@ -925,3 +925,53 @@ virAdmServerLookupClient(virAdmServerPtr srv,
virDispatchError(NULL); virDispatchError(NULL);
return NULL; return NULL;
} }
/**
* virAdmClientGetInfo:
* @client: a client object reference
* @params: pointer to a list of typed parameters which will be allocated
* to store all returned parameters
* @nparams: pointer which will hold the number of params returned in @params
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Extract identity information about a client. Attributes returned in @params
* are mostly transport-dependent, i.e. some attributes including client
* process's pid, gid, uid, or remote side's socket address are only available
* for a specific connection type - local vs remote.
* Other identity attributes like authentication method used
* (if authentication is enabled on the remote host), SELinux context, or
* an indicator whether client is connected via a read-only connection are
* independent of the connection transport.
*
* Note that the read-only connection indicator returns false for TCP/TLS
* clients because libvirt treats such connections as read-write by default,
* even though a TCP client is able to restrict access to certain APIs for
* itself.
*
* Returns 0 if the information has been successfully retrieved or -1 in case
* of an error.
*/
int
virAdmClientGetInfo(virAdmClientPtr client,
virTypedParameterPtr *params,
int *nparams,
unsigned int flags)
{
int ret = -1;
VIR_DEBUG("client=%p, params=%p, nparams=%p, flags=%x",
client, params, nparams, flags);
virResetLastError();
virCheckAdmClientReturn(client, -1);
virCheckNonNullArgGoto(params, error);
virCheckFlagsGoto(0, error);
if ((ret = remoteAdminClientGetInfo(client, params, nparams, flags)) < 0)
goto error;
return ret;
error:
virDispatchError(NULL);
return -1;
}

View File

@ -6,6 +6,8 @@
# #
# admin/admin_protocol.x # admin/admin_protocol.x
xdr_admin_client_get_info_args;
xdr_admin_client_get_info_ret;
xdr_admin_connect_get_lib_version_ret; xdr_admin_connect_get_lib_version_ret;
xdr_admin_connect_list_servers_args; xdr_admin_connect_list_servers_args;
xdr_admin_connect_list_servers_ret; xdr_admin_connect_list_servers_ret;

View File

@ -33,4 +33,5 @@ LIBVIRT_ADMIN_1.3.0 {
virAdmConnectLookupServer; virAdmConnectLookupServer;
virAdmServerSetThreadPoolParameters; virAdmServerSetThreadPoolParameters;
virAdmServerListClients; virAdmServerListClients;
virAdmClientGetInfo;
}; };