uid_t callerUid;
gid_t callerGid;
pid_t callerPid;
+ unsigned long long timestamp;
/* If the client is root then we want to bypass the
* policykit auth to avoid root being denied if
*/
if (auth == VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
- &callerPid) < 0) {
+ &callerPid, ×tamp) < 0) {
/* Don't do anything on error - it'll be validated at next
* phase of auth anyway */
virResetLastError();
pid_t callerPid = -1;
gid_t callerGid = -1;
uid_t callerUid = -1;
+ unsigned long long timestamp;
const char *action;
int status = -1;
char *ident = NULL;
}
if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
- &callerPid) < 0) {
+ &callerPid, ×tamp) < 0) {
goto authfail;
}
(long long) callerPid, callerUid);
virCommandAddArg(cmd, "--process");
- virCommandAddArgFormat(cmd, "%lld", (long long) callerPid);
+ if (timestamp != 0) {
+ virCommandAddArgFormat(cmd, "%lld,%llu", (long long) callerPid, timestamp);
+ } else {
+ virCommandAddArgFormat(cmd, "%lld", (long long) callerPid);
+ }
virCommandAddArg(cmd, "--allow-user-interaction");
if (virAsprintf(&ident, "pid:%lld,uid:%d",
virStringArrayHasString;
virStringFreeList;
virStringJoin;
+virStringListLength;
virStringSplit;
virStrncpy;
virStrndup;
virLockDaemonClientPtr priv;
uid_t clientuid;
gid_t clientgid;
+ unsigned long long timestamp;
bool privileged = opaque != NULL;
if (VIR_ALLOC(priv) < 0) {
if (virNetServerClientGetUNIXIdentity(client,
&clientuid,
&clientgid,
- &priv->clientPid) < 0)
+ &priv->clientPid,
+ ×tamp) < 0)
goto error;
VIR_DEBUG("New client pid %llu uid %llu",
int virNetServerClientGetUNIXIdentity(virNetServerClientPtr client,
- uid_t *uid, gid_t *gid, pid_t *pid)
+ uid_t *uid, gid_t *gid, pid_t *pid,
+ unsigned long long *timestamp)
{
int ret = -1;
virObjectLock(client);
if (client->sock)
- ret = virNetSocketGetUNIXIdentity(client->sock, uid, gid, pid);
+ ret = virNetSocketGetUNIXIdentity(client->sock,
+ uid, gid, pid,
+ timestamp);
virObjectUnlock(client);
return ret;
}
virNetServerClientCreateIdentity(virNetServerClientPtr client)
{
char *processid = NULL;
+ char *processtime = NULL;
char *username = NULL;
char *groupname = NULL;
#if WITH_SASL
gid_t gid;
uid_t uid;
pid_t pid;
- if (virNetSocketGetUNIXIdentity(client->sock, &uid, &gid, &pid) < 0)
+ unsigned long long timestamp;
+ if (virNetSocketGetUNIXIdentity(client->sock,
+ &uid, &gid, &pid,
+ ×tamp) < 0)
goto cleanup;
if (!(username = virGetUserName(uid)))
goto cleanup;
if (!(groupname = virGetGroupName(gid)))
goto cleanup;
- if (virAsprintf(&processid, "%lld",
- (long long)pid) < 0) {
+ if (virAsprintf(&processid, "%llu",
+ (unsigned long long)pid) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ if (virAsprintf(&processtime, "%llu",
+ timestamp) < 0) {
virReportOOMError();
goto cleanup;
}
VIR_IDENTITY_ATTR_UNIX_PROCESS_ID,
processid) < 0)
goto error;
+ if (processtime &&
+ virIdentitySetAttr(ret,
+ VIR_IDENTITY_ATTR_UNIX_PROCESS_TIME,
+ processtime) < 0)
+ goto error;
#if HAVE_SASL
if (saslname &&
virIdentitySetAttr(ret,
VIR_FREE(username);
VIR_FREE(groupname);
VIR_FREE(processid);
+ VIR_FREE(processtime);
VIR_FREE(seccontext);
#if HAVE_SASL
VIR_FREE(saslname);
bool virNetServerClientIsLocal(virNetServerClientPtr client);
int virNetServerClientGetUNIXIdentity(virNetServerClientPtr client,
- uid_t *uid, gid_t *gid, pid_t *pid);
+ uid_t *uid, gid_t *gid, pid_t *pid,
+ unsigned long long *timestamp);
int virNetServerClientGetSELinuxContext(virNetServerClientPtr client,
char **context);
int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
uid_t *uid,
gid_t *gid,
- pid_t *pid)
+ pid_t *pid,
+ unsigned long long *timestamp)
{
struct ucred cr;
socklen_t cr_len = sizeof(cr);
+ int ret = -1;
+
virObjectLock(sock);
if (getsockopt(sock->fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) < 0) {
virReportSystemError(errno, "%s",
_("Failed to get client socket identity"));
- virObjectUnlock(sock);
- return -1;
+ goto cleanup;
}
+ if (virProcessGetStartTime(cr.pid, timestamp) < 0)
+ goto cleanup;
+
*pid = cr.pid;
*uid = cr.uid;
*gid = cr.gid;
+ ret = 0;
+
+cleanup:
virObjectUnlock(sock);
- return 0;
+ return ret;
}
#elif defined(LOCAL_PEERCRED)
+
int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
uid_t *uid,
gid_t *gid,
- pid_t *pid)
+ pid_t *pid,
+ unsigned long long *timestamp ATTRIBUTE_UNUSED)
{
struct xucred cr;
socklen_t cr_len = sizeof(cr);
int virNetSocketGetUNIXIdentity(virNetSocketPtr sock ATTRIBUTE_UNUSED,
uid_t *uid ATTRIBUTE_UNUSED,
gid_t *gid ATTRIBUTE_UNUSED,
- pid_t *pid ATTRIBUTE_UNUSED)
+ pid_t *pid ATTRIBUTE_UNUSED,
+ unsigned long long *timestamp ATTRIBUTE_UNUSED)
{
/* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
virReportSystemError(ENOSYS, "%s",
int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
uid_t *uid,
gid_t *gid,
- pid_t *pid);
+ pid_t *pid,
+ unsigned long long *timestamp);
int virNetSocketGetSELinuxContext(virNetSocketPtr sock,
char **context);
VIR_IDENTITY_ATTR_UNIX_USER_NAME,
VIR_IDENTITY_ATTR_UNIX_GROUP_NAME,
VIR_IDENTITY_ATTR_UNIX_PROCESS_ID,
+ VIR_IDENTITY_ATTR_UNIX_PROCESS_TIME,
VIR_IDENTITY_ATTR_SASL_USER_NAME,
VIR_IDENTITY_ATTR_X509_DISTINGUISHED_NAME,
VIR_IDENTITY_ATTR_SELINUX_CONTEXT,
#endif
#include <sched.h>
+#ifdef __FreeBSD__
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/user.h>
+#endif
+
+#include "viratomic.h"
#include "virprocess.h"
#include "virerror.h"
#include "viralloc.h"
return -1;
}
#endif /* ! (HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)) */
+
+#ifdef __linux__
+/*
+ * Port of code from polkitunixprocess.c under terms
+ * of the LGPLv2+
+ */
+int virProcessGetStartTime(pid_t pid,
+ unsigned long long *timestamp)
+{
+ char *filename = NULL;
+ char *buf = NULL;
+ char *tmp;
+ int ret = -1;
+ int len;
+ char **tokens = NULL;
+
+ if (virAsprintf(&filename, "/proc/%llu/stat",
+ (unsigned long long)pid) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if ((len = virFileReadAll(filename, 1024, &buf)) < 0)
+ goto cleanup;
+
+ /* start time is the token at index 19 after the '(process name)' entry - since only this
+ * field can contain the ')' character, search backwards for this to avoid malicious
+ * processes trying to fool us
+ */
+
+ if (!(tmp = strrchr(buf, ')'))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot find start time in %s"),
+ filename);
+ goto cleanup;
+ }
+ tmp += 2; /* skip ') ' */
+ if ((tmp - buf) >= len) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot find start time in %s"),
+ filename);
+ goto cleanup;
+ }
+
+ tokens = virStringSplit(tmp, " ", 0);
+
+ if (virStringListLength(tokens) < 20) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot find start time in %s"),
+ filename);
+ goto cleanup;
+ }
+
+ if (virStrToLong_ull(tokens[19],
+ NULL,
+ 10,
+ timestamp) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse start time %s in %s"),
+ tokens[19], filename);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virStringFreeList(tokens);
+ VIR_FREE(filename);
+ VIR_FREE(buf);
+ return ret;
+}
+#elif defined(__FreeBSD__)
+int virProcessGetStartTime(pid_t pid,
+ unsigned long long *timestamp)
+{
+ struct kinfo_proc p;
+ int mib[4];
+ size_t len = 4;
+
+ sysctlnametomib("kern.proc.pid", mib, &len);
+
+ len = sizeof(struct kinfo_proc);
+ mib[3] = pid;
+
+ if (sysctl(mib, 4, &p, &len, NULL, 0) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to query process ID start time"));
+ return -1;
+ }
+
+ *timestamp = (unsigned long long)p.ki_start.tv_sec;
+
+ return 0;
+
+}
+#else
+int virProcessGetStartTime(pid_t pid,
+ unsigned long long *timestamp)
+{
+ static int warned = 0;
+ if (virAtomicIntInc(&warned) == 1) {
+ VIR_WARN("Process start time of pid %llu not available on this platform",
+ (unsigned long long)pid);
+ warned = true;
+ }
+ *timestamp = 0;
+ return 0;
+}
+#endif
virBitmapPtr *map,
int maxcpu);
+int virProcessGetStartTime(pid_t pid,
+ unsigned long long *timestamp);
+
int virProcessGetNamespaces(pid_t pid,
size_t *nfdlist,
int **fdlist);
return 1;
}
+
+
+size_t virStringListLength(char **strings)
+{
+ size_t i = 0;
+
+ while (strings && strings[i])
+ i++;
+
+ return i;
+}
ATTRIBUTE_RETURN_CHECK;
# define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest))
-
/* Don't call these directly - use the macros below */
int virStrdup(char **dest, const char *src, bool report, int domcode,
const char *filename, const char *funcname, size_t linenr)
*/
# define VIR_STRNDUP_QUIET(dst, src, n) virStrndup(&(dst), src, n, false, \
0, NULL, NULL, 0)
+
+size_t virStringListLength(char **strings);
+
#endif /* __VIR_STRING_H__ */