diff --git a/Xext/security.c b/Xext/security.c
index 162d07ae0..23c1a3899 100644
--- a/Xext/security.c
+++ b/Xext/security.c
@@ -40,6 +40,9 @@ in this Software without prior written authorization from The Open Group.
 #include <X11/extensions/securproto.h>
 #include "extinit.h"
 #include "protocol-versions.h"
+#include <sys/socket.h>
+#include "../os/osdep.h"
+#include <X11/Xtrans/Xtransint.h>
 
 /* Extension stuff */
 static int SecurityErrorBase;   /* first Security error number */
@@ -53,6 +56,8 @@ static CallbackListPtr SecurityValidateGroupCallback = NULL;
 /* Private state record */
 static DevPrivateKeyRec stateKeyRec;
 
+static int x11_root_gid;
+
 #define stateKey (&stateKeyRec)
 
 /* This is what we store as client security state */
@@ -61,6 +66,8 @@ typedef struct {
     unsigned int live       :1;
     unsigned int trustLevel :2;
     XID authId;
+    int pid;
+    int gid; /* -1 if unable to get gid */
 } SecurityStateRec;
 
 /* The only extensions that untrusted clients have access to */
@@ -110,6 +117,83 @@ SecurityAudit(const char *format, ...)
     va_end(args);
 }                               /* SecurityAudit */
 
+static int
+ProgramHasX11RootPermission(int pid) {
+    if(pid == 0)
+        return 1;
+    if(pid == -1)
+        return 0;
+
+    char remote_connection_proc[128];
+    snprintf(remote_connection_proc, sizeof(remote_connection_proc), "/proc/%d/exe", pid);
+
+    char remote_program_full_path[PATH_MAX];
+    ssize_t remote_program_full_path_len = 0;
+    remote_program_full_path_len = readlink(remote_connection_proc, remote_program_full_path, sizeof(remote_program_full_path) - 1);
+    if(remote_program_full_path_len != -1) {
+        remote_program_full_path[remote_program_full_path_len] = '\0';
+        const char *root_access_programs[] = {
+            "/usr/local/bin/dwm",
+            "/usr/bin/xinit",
+            "/usr/bin/xrdb",
+            "/usr/bin/xsetroot",
+            "/usr/bin/feh",
+            "/usr/bin/nvidia-settings",
+            "/usr/lib/kdeconnectd"
+        };
+
+        for(int i = 0; i < 4; ++i) {
+            if(strcmp(remote_program_full_path, root_access_programs[i]) == 0)
+                return 1;
+        }
+    }
+
+    return 0;
+}
+
+#define RootWindowPtr NULL
+
+static int
+ClientIsSameProcess(ClientPtr client, ClientPtr other_client) {
+    SecurityStateRec *subj, *obj;
+    subj = dixLookupPrivate(&client->devPrivates, stateKey);
+    obj = dixLookupPrivate(&other_client->devPrivates, stateKey);
+    return subj->pid == obj->pid;
+}
+
+static int
+ClientHasAccessToWindow(SecurityStateRec *subj, ClientPtr client, WindowPtr window) {
+    if(window != RootWindowPtr && wClient(window) == client)
+        return Success;
+    if(subj->gid == x11_root_gid)
+        return Success;
+    if(subj->pid != -1 && window && wClient(window) && ClientIsSameProcess(client, wClient(window))) /* Multiple Display connections in the same process */
+        return Success;
+    if(ProgramHasX11RootPermission(subj->pid))
+        return Success;
+
+    return BadAccess;
+}
+
+static int
+ClientHasAccessToClient(SecurityStateRec *subj, ClientPtr client, ClientPtr other_client) {
+    if(client == other_client)
+        return Success;
+    if(subj->gid == x11_root_gid)
+        return Success;
+    if(subj->pid != -1 && other_client && ClientIsSameProcess(client, other_client)) /* Multiple Display connections in the same process */
+        return Success;
+    if(ProgramHasX11RootPermission(subj->pid))
+        return Success;
+
+    return BadAccess;
+}
+
 /*
  * Performs a Security permission check.
  */
@@ -142,6 +226,8 @@ SecurityLabelInitial(void)
     state->trustLevel = XSecurityClientTrusted;
     state->haveState = TRUE;
     state->live = FALSE;
+    state->pid = 0;
+    state->gid = x11_root_gid;
 }
 
 /*
@@ -706,7 +792,8 @@ SecurityDevice(CallbackListPtr *pcbl, void *unused, void *calldata)
         /* this extension only supports the core keyboard */
         allowed = requested;
 
-    if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
+    // TODO: Readd permission check
+    if (/*ClientHasAccessToWindow(subj, rec->client, RootWindowPtr) != Success || */SecurityDoCheck(subj, obj, requested, allowed) != Success) {
         SecurityAudit("Security denied client %d keyboard access on request "
                       "%s\n", rec->client->index,
                       SecurityLookupRequestName(rec->client));
@@ -772,6 +859,8 @@ SecurityResource(CallbackListPtr *pcbl, void *unused, void *calldata)
 
     if (clients[cid] != NULL) {
         obj = dixLookupPrivate(&clients[cid]->devPrivates, stateKey);
+        if(cid != 0 && ClientHasAccessToClient(subj, rec->client, clients[cid]) == Success)
+            return;
         if (SecurityDoCheck(subj, obj, requested, allowed) == Success)
             return;
     }
@@ -817,7 +906,7 @@ SecurityServer(CallbackListPtr *pcbl, void *unused, void *calldata)
     subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
     obj = dixLookupPrivate(&serverClient->devPrivates, stateKey);
 
-    if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
+    if (ClientHasAccessToWindow(subj, rec->client, RootWindowPtr) != Success || SecurityDoCheck(subj, obj, requested, allowed) != Success) {
         SecurityAudit("Security: denied client %d access to server "
                       "configuration request %s\n", rec->client->index,
                       SecurityLookupRequestName(rec->client));
@@ -836,7 +925,7 @@ SecurityClient(CallbackListPtr *pcbl, void *unused, void *calldata)
     subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
     obj = dixLookupPrivate(&rec->target->devPrivates, stateKey);
 
-    if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
+    if (ClientHasAccessToClient(subj, rec->client, rec->target) != Success || SecurityDoCheck(subj, obj, requested, allowed) != Success) {
         SecurityAudit("Security: denied client %d access to client %d on "
                       "request %s\n", rec->client->index, rec->target->index,
                       SecurityLookupRequestName(rec->client));
@@ -856,7 +945,7 @@ SecurityProperty(CallbackListPtr *pcbl, void *unused, void *calldata)
     subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
     obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
 
-    if (SecurityDoCheck(subj, obj, requested, allowed) != Success) {
+    if (ClientHasAccessToWindow(subj, rec->client, rec->pWin) != Success || SecurityDoCheck(subj, obj, requested, allowed) != Success) {
         SecurityAudit("Security: denied client %d access to property %s "
                       "(atom 0x%x) window 0x%lx of client %d on request %s\n",
                       rec->client->index, NameForAtom(name), name,
@@ -878,7 +967,7 @@ SecuritySend(CallbackListPtr *pcbl, void *unused, void *calldata)
         subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
         obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
 
-        if (SecurityDoCheck(subj, obj, DixSendAccess, 0) == Success)
+        if (ClientHasAccessToWindow(subj, rec->client, rec->pWin) == Success && SecurityDoCheck(subj, obj, DixSendAccess, 0) == Success)
             return;
 
         for (i = 0; i < rec->count; i++)
@@ -907,7 +996,7 @@ SecurityReceive(CallbackListPtr *pcbl, void *unused, void *calldata)
     subj = dixLookupPrivate(&rec->client->devPrivates, stateKey);
     obj = dixLookupPrivate(&wClient(rec->pWin)->devPrivates, stateKey);
 
-    if (SecurityDoCheck(subj, obj, DixReceiveAccess, 0) == Success)
+    if (ClientHasAccessToWindow(subj, rec->client, rec->pWin) == Success && SecurityDoCheck(subj, obj, DixReceiveAccess, 0) == Success)
         return;
 
     SecurityAudit("Security: denied client %d from receiving an event "
@@ -955,6 +1044,17 @@ SecurityClientState(CallbackListPtr *pcbl, void *unused, void *calldata)
         state->authId = None;
         state->haveState = TRUE;
         state->live = FALSE;
+        if(((OsCommPtr)pci->client->osPrivate)->trans_conn) {
+            state->pid = ((OsCommPtr)pci->client->osPrivate)->trans_conn->remote_info.pid;
+            state->gid = ((OsCommPtr)pci->client->osPrivate)->trans_conn->remote_info.gid;
+        } else {
+            state->pid = -1;
+            state->gid = -1;
+        }
         break;
 
     case ClientStateRunning:
@@ -1020,6 +1120,39 @@ SecurityResetProc(ExtensionEntry * extEntry)
     XaceDeleteCallback(XACE_SERVER_ACCESS, SecurityServer, NULL);
 }
 
+/* TODO: Windows */
+static int
+local_group_get_id_by_name(const char *name, int fallback_value) {
+    int gid = fallback_value;
+    FILE *file = fopen("/etc/group", "rb");
+    if(!file)
+        FatalError("SecurityExtensionSetup: Failed to read /etc/group.\n");
+
+    char line_buffer[256];
+    while(fgets(line_buffer, sizeof(line_buffer), file)) {
+        /* Group name */
+        char *tok = strtok(line_buffer, ":");
+        if(!tok || strcmp(tok, name) != 0)
+            continue;
+
+        /* Encrypted password */
+        tok = strtok(NULL, ":");
+        if(!tok)
+            continue;
+
+        /* Group id */
+        tok = strtok(NULL, ":\n");
+        if(!tok)
+            continue;
+
+        gid = atoi(tok);
+        break;
+    }
+
+    fclose(file);
+    return gid;
+}
+
 /* SecurityExtensionInit
  *
  * Arguments: none.
@@ -1049,6 +1182,8 @@ SecurityExtensionInit(void)
 
     RTEventClient |= RC_NEVERRETAIN;
 
+    x11_root_gid = local_group_get_id_by_name("x11-root", 0);
+
     /* Allocate the private storage */
     if (!dixRegisterPrivateKey
         (stateKey, PRIVATE_CLIENT, sizeof(SecurityStateRec)))
@@ -1087,4 +1222,8 @@ SecurityExtensionInit(void)
 
     /* Label objects that were created before we could register ourself */
     SecurityLabelInitial();
 }

