From: "Daniel P. Berrange" <berrange(a)redhat.com>
Add APIs which allow storage of a real & effective identity on
all server clients. Also add an API which allows creation of an
initial identity based on the results of client authentication
processes like TLS, x509, SASL, SO_PEERCRED
---
src/rpc/virnetserverclient.c | 152 ++++++++++++++++++++++++++++++++++++++++++
src/rpc/virnetserverclient.h | 11 +++
2 files changed, 163 insertions(+)
diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c
index 1e9d3db..9647ac3 100644
--- a/src/rpc/virnetserverclient.c
+++ b/src/rpc/virnetserverclient.c
@@ -75,6 +75,10 @@ struct _virNetServerClient
int sockTimer; /* Timer to be fired upon cached data,
* so we jump out from poll() immediately */
+
+ virIdentityPtr realIdentity;
+ virIdentityPtr effectiveIdentity;
+
/* Count of messages in the 'tx' queue,
* and the server worker pool queue
* ie RPC calls in progress. Does not count
@@ -487,6 +491,149 @@ int virNetServerClientGetUNIXIdentity(virNetServerClientPtr client,
}
+virIdentityPtr virNetServerClientGetIdentity(virNetServerClientPtr client)
+{
+ char *processid = NULL;
+ char *username = NULL;
+ char *groupname = NULL;
+#if HAVE_SASL
+ char *saslname = NULL;
+#endif
+ char *x509dname = NULL;
+ char *seccontext = NULL;
+ virIdentityPtr ret = NULL;
+ virNetSASLSessionPtr sasl;
+ virNetTLSSessionPtr tls;
+
+ if (virNetServerClientIsLocal(client)) {
+ gid_t gid;
+ uid_t uid;
+ pid_t pid;
+ if (virNetServerClientGetUNIXIdentity(client, &uid, &gid, &pid) <
0)
+ goto cleanup;
+
+ if (!(username = virGetUserName(uid)))
+ goto cleanup;
+ if (!(groupname = virGetGroupName(gid)))
+ goto cleanup;
+ if (virAsprintf(&processid, "%d", (int)pid) < 0)
+ goto cleanup;
+ }
+
+#if HAVE_SASL
+ if ((sasl = virNetServerClientGetSASLSession(client))) {
+ const char *identity = virNetSASLSessionGetIdentity(sasl);
+ if (identity &&
+ !(saslname = strdup(identity))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+#endif
+
+ if ((tls = virNetServerClientGetTLSSession(client))) {
+ const char *identity = virNetTLSSessionGetX509DName(tls);
+ if (identity &&
+ !(x509dname = strdup(identity))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+
+ if (virNetServerClientGetSecurityContext(client, &seccontext) < 0)
+ goto cleanup;
+
+ if (!(ret = virIdentityNew()))
+ goto cleanup;
+
+ if (username &&
+ virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_UNIX_USER_NAME, username) < 0)
+ goto error;
+ if (groupname &&
+ virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_UNIX_GROUP_NAME, groupname) < 0)
+ goto error;
+ if (processid &&
+ virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_UNIX_PROCESS_ID, processid) < 0)
+ goto error;
+#if HAVE_SASL
+ if (saslname &&
+ virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_SASL_USER_NAME, saslname) < 0)
+ goto error;
+#endif
+ if (x509dname &&
+ virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_X509_DISTINGUISHED_NAME, x509dname)
< 0)
+ goto error;
+ if (seccontext &&
+ virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_SECURITY_CONTEXT, seccontext) < 0)
+ goto error;
+
+cleanup:
+ VIR_FREE(username);
+ VIR_FREE(groupname);
+ VIR_FREE(processid);
+ VIR_FREE(seccontext);
+#if HAVE_SASL
+ VIR_FREE(saslname);
+#endif
+ VIR_FREE(x509dname);
+ return ret;
+
+error:
+ virIdentityFree(ret);
+ ret = NULL;
+ goto cleanup;
+}
+
+
+virIdentityPtr virNetServerClientGetRealIdentity(virNetServerClientPtr client)
+{
+ virIdentityPtr ret;
+ virNetServerClientLock(client);
+ ret = client->realIdentity;
+ if (ret)
+ virIdentityRef(ret);
+ virNetServerClientUnlock(client);
+ return ret;
+}
+
+
+virIdentityPtr virNetServerClientGetEffectiveIdentity(virNetServerClientPtr client)
+{
+ virIdentityPtr ret;
+ virNetServerClientLock(client);
+ ret = client->effectiveIdentity;
+ if (ret)
+ virIdentityRef(ret);
+ virNetServerClientUnlock(client);
+ return ret;
+}
+
+
+void virNetServerClientSetRealIdentity(virNetServerClientPtr client,
+ virIdentityPtr ident)
+{
+ virNetServerClientLock(client);
+ if (client->realIdentity)
+ virIdentityFree(client->realIdentity);
+ if (ident)
+ virIdentityRef(ident);
+ client->realIdentity = ident;
+ virNetServerClientUnlock(client);
+}
+
+void virNetServerClientSetEffectiveIdentity(virNetServerClientPtr client,
+ virIdentityPtr ident)
+{
+ virNetServerClientLock(client);
+ if (client->effectiveIdentity)
+ virIdentityFree(client->effectiveIdentity);
+ if (ident)
+ virIdentityRef(ident);
+ client->effectiveIdentity = ident;
+ virNetServerClientUnlock(client);
+}
+
+
int virNetServerClientGetSecurityContext(virNetServerClientPtr client,
char **context)
{
@@ -625,6 +772,11 @@ void virNetServerClientFree(virNetServerClientPtr client)
return;
}
+ if (client->realIdentity)
+ virIdentityFree(client->realIdentity);
+ if (client->effectiveIdentity)
+ virIdentityFree(client->effectiveIdentity);
+
if (client->privateData &&
client->privateDataFreeFunc)
client->privateDataFreeFunc(client->privateData);
diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h
index a3b37a3..7435eee 100644
--- a/src/rpc/virnetserverclient.h
+++ b/src/rpc/virnetserverclient.h
@@ -77,6 +77,17 @@ int virNetServerClientGetUNIXIdentity(virNetServerClientPtr client,
int virNetServerClientGetSecurityContext(virNetServerClientPtr client,
char **context);
+virIdentityPtr virNetServerClientGetIdentity(virNetServerClientPtr client);
+
+virIdentityPtr virNetServerClientGetRealIdentity(virNetServerClientPtr client);
+virIdentityPtr virNetServerClientGetEffectiveIdentity(virNetServerClientPtr client);
+
+void virNetServerClientSetRealIdentity(virNetServerClientPtr client,
+ virIdentityPtr ident);
+void virNetServerClientSetEffectiveIdentity(virNetServerClientPtr client,
+ virIdentityPtr iden);
+
+
void virNetServerClientRef(virNetServerClientPtr client);
typedef void (*virNetServerClientFreeFunc)(void *data);
--
1.7.10