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(a)redhat.com>
---
daemon/admin.c | 59 ++++++++++++++++++++++++++
daemon/admin_server.c | 92 +++++++++++++++++++++++++++++++++++++++++
daemon/admin_server.h | 5 +++
include/libvirt/libvirt-admin.h | 5 +++
src/admin/admin_protocol.x | 19 ++++++++-
src/admin/admin_remote.c | 47 +++++++++++++++++++++
src/admin_protocol-structs | 11 +++++
src/libvirt-admin.c | 39 +++++++++++++++++
src/libvirt_admin_private.syms | 2 +
src/libvirt_admin_public.syms | 1 +
10 files changed, 279 insertions(+), 1 deletion(-)
diff --git a/daemon/admin.c b/daemon/admin.c
index fcbdee5..3de09ca 100644
--- a/daemon/admin.c
+++ b/daemon/admin.c
@@ -236,4 +236,63 @@ adminDispatchServerSetThreadpoolParameters(virNetServerPtr server
ATTRIBUTE_UNUS
virObjectUnref(srv);
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, ¶ms, &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"
diff --git a/daemon/admin_server.c b/daemon/admin_server.c
index 9ea1164..2fc4675 100644
--- a/daemon/admin_server.c
+++ b/daemon/admin_server.c
@@ -27,6 +27,7 @@
#include "datatypes.h"
#include "viralloc.h"
#include "virerror.h"
+#include "viridentity.h"
#include "virlog.h"
#include "virnetdaemon.h"
#include "virnetserver.h"
@@ -211,3 +212,94 @@ adminServerLookupClient(virNetServerPtr srv,
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;
+}
diff --git a/daemon/admin_server.h b/daemon/admin_server.h
index a593251..95c76b9 100644
--- a/daemon/admin_server.h
+++ b/daemon/admin_server.h
@@ -54,4 +54,9 @@ virNetServerClientPtr adminServerLookupClient(virNetServerPtr srv,
unsigned long long id,
unsigned int flags);
+int adminClientGetInfo(virNetServerClientPtr client,
+ virTypedParameterPtr *params,
+ int *nparams,
+ unsigned int flags);
+
#endif /* __LIBVIRTD_ADMIN_SERVER_H__ */
diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h
index 5c30aae..0a1ea61 100644
--- a/include/libvirt/libvirt-admin.h
+++ b/include/libvirt/libvirt-admin.h
@@ -344,6 +344,11 @@ virAdmServerLookupClient(virAdmServerPtr srv,
# define VIR_CLIENT_INFO_SELINUX_CONTEXT "selinux_context"
+int virAdmClientGetInfo(virAdmClientPtr client,
+ virTypedParameterPtr *params,
+ int *nparams,
+ unsigned int flags);
+
# ifdef __cplusplus
}
# endif
diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x
index da21db8..67bdbf3 100644
--- a/src/admin/admin_protocol.x
+++ b/src/admin/admin_protocol.x
@@ -42,6 +42,9 @@ const ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX = 32;
/* Upper limit on list of clients */
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. */
typedef string admin_nonnull_string<ADMIN_STRING_MAX>;
@@ -148,6 +151,15 @@ struct admin_server_lookup_client_ret {
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. */
const ADMIN_PROGRAM = 0x06900690;
const ADMIN_PROTOCOL_VERSION = 1;
@@ -213,5 +225,10 @@ enum admin_procedure {
/**
* @generate: both
*/
- ADMIN_PROC_SERVER_LOOKUP_CLIENT = 9
+ ADMIN_PROC_SERVER_LOOKUP_CLIENT = 9,
+
+ /**
+ * @generate: none
+ */
+ ADMIN_PROC_CLIENT_GET_INFO = 10
};
diff --git a/src/admin/admin_remote.c b/src/admin/admin_remote.c
index b833ea4..40fcddb 100644
--- a/src/admin/admin_remote.c
+++ b/src/admin/admin_remote.c
@@ -67,6 +67,16 @@ make_nonnull_server(admin_nonnull_server *srv_dst, virAdmServerPtr
srv_src)
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
callFull(virAdmConnectPtr conn ATTRIBUTE_UNUSED,
remoteAdminPrivPtr priv,
@@ -308,3 +318,40 @@ remoteAdminServerSetThreadPoolParameters(virAdmServerPtr srv,
virObjectUnlock(priv);
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;
+}
diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs
index dc2220e..ea9adf6 100644
--- a/src/admin_protocol-structs
+++ b/src/admin_protocol-structs
@@ -95,6 +95,16 @@ struct admin_server_lookup_client_args {
struct admin_server_lookup_client_ret {
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 {
ADMIN_PROC_CONNECT_OPEN = 1,
ADMIN_PROC_CONNECT_CLOSE = 2,
@@ -105,4 +115,5 @@ enum admin_procedure {
ADMIN_PROC_SERVER_SET_THREADPOOL_PARAMETERS = 7,
ADMIN_PROC_SERVER_LIST_CLIENTS = 8,
ADMIN_PROC_SERVER_LOOKUP_CLIENT = 9,
+ ADMIN_PROC_CLIENT_GET_INFO = 10,
};
diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c
index 5d0755f..01094e6 100644
--- a/src/libvirt-admin.c
+++ b/src/libvirt-admin.c
@@ -925,3 +925,42 @@ virAdmServerLookupClient(virAdmServerPtr srv,
virDispatchError(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 information about a client. This information regards connection
+ * parameters, namely transport, authentication method, pid, gid, uid, etc.
+ *
+ * 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;
+}
diff --git a/src/libvirt_admin_private.syms b/src/libvirt_admin_private.syms
index 3d7ecbc..affe8c1 100644
--- a/src/libvirt_admin_private.syms
+++ b/src/libvirt_admin_private.syms
@@ -6,6 +6,8 @@
#
# 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_list_servers_args;
xdr_admin_connect_list_servers_ret;
diff --git a/src/libvirt_admin_public.syms b/src/libvirt_admin_public.syms
index 066ae0c..27e4a1d 100644
--- a/src/libvirt_admin_public.syms
+++ b/src/libvirt_admin_public.syms
@@ -33,4 +33,5 @@ LIBVIRT_ADMIN_1.3.0 {
virAdmConnectLookupServer;
virAdmServerSetThreadPoolParameters;
virAdmServerListClients;
+ virAdmClientGetInfo;
};
--
2.4.11