From 4a0e91082522addf852c7fc49609dc19068c5d26 Mon Sep 17 00:00:00 2001 From: Erik Skultety Date: Fri, 22 Apr 2016 13:05:42 +0200 Subject: [PATCH] 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 --- 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 | 50 ++++++++++++++++++ src/libvirt_admin_private.syms | 2 + src/libvirt_admin_public.syms | 1 + 10 files changed, 290 insertions(+), 1 deletion(-) diff --git a/daemon/admin.c b/daemon/admin.c index fcbdee5fa3..3de09ca900 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 9ea1164571..2fc467539c 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 a593251d7a..95c76b9e0f 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 5c30aae125..0a1ea61e33 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 da21db8d39..67bdbf30ee 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; @@ -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; +}; + /* 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 b833ea4e15..40fcddb5fb 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 dc2220e3ef..ea9adf6c3c 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 d9cdb811f1..a94f5dd1d3 100644 --- a/src/libvirt-admin.c +++ b/src/libvirt-admin.c @@ -925,3 +925,53 @@ 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 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; +} diff --git a/src/libvirt_admin_private.syms b/src/libvirt_admin_private.syms index 3d7ecbcb71..affe8c1133 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 066ae0ce98..27e4a1deed 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; };