Blame 08-vnc-acl-mgmt.patch

Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/Makefile
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/Makefile
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/Makefile
Glauber Costa 47b075
@@ -148,7 +148,7 @@ endif
Glauber Costa 47b075
 ifdef CONFIG_CURSES
Glauber Costa 47b075
 OBJS+=curses.o
Glauber Costa 47b075
 endif
Glauber Costa 47b075
-OBJS+=vnc.o d3des.o
Glauber Costa 47b075
+OBJS+=vnc.o acl.o d3des.o
Glauber Costa 47b075
 ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
 OBJS+=vnc-tls.o vnc-auth-vencrypt.o
Glauber Costa 47b075
 endif
Glauber Costa 47b075
@@ -178,9 +178,11 @@ sdl.o: sdl.c keymaps.h sdl_keysym.h
Glauber Costa 47b075
 
Glauber Costa 47b075
 sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS)
Glauber Costa 47b075
 
Glauber Costa 47b075
+acl.o: acl.h acl.c
Glauber Costa 47b075
+
Glauber Costa 47b075
 vnc.h: vnc-tls.h vnc-auth-vencrypt.h vnc-auth-sasl.h keymaps.h
Glauber Costa 47b075
 
Glauber Costa 47b075
-vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h
Glauber Costa 47b075
+vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h acl.h
Glauber Costa 47b075
 
Glauber Costa 47b075
 vnc.o: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
Glauber Costa 47b075
 
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/acl.c
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- /dev/null
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/acl.c
Glauber Costa 47b075
@@ -0,0 +1,185 @@
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * QEMU access control list management
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Copyright (C) 2009 Red Hat, Inc
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Glauber Costa 47b075
+ * of this software and associated documentation files (the "Software"), to deal
Glauber Costa 47b075
+ * in the Software without restriction, including without limitation the rights
Glauber Costa 47b075
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Glauber Costa 47b075
+ * copies of the Software, and to permit persons to whom the Software is
Glauber Costa 47b075
+ * furnished to do so, subject to the following conditions:
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * The above copyright notice and this permission notice shall be included in
Glauber Costa 47b075
+ * all copies or substantial portions of the Software.
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Glauber Costa 47b075
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Glauber Costa 47b075
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Glauber Costa 47b075
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Glauber Costa 47b075
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Glauber Costa 47b075
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Glauber Costa 47b075
+ * THE SOFTWARE.
Glauber Costa 47b075
+ */
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+#include "qemu-common.h"
Glauber Costa 47b075
+#include "sysemu.h"
Glauber Costa 47b075
+#include "acl.h"
Glauber Costa 47b075
+
Glauber Costa 47b075
+#ifdef HAVE_FNMATCH_H
Glauber Costa 47b075
+#include <fnmatch.h>
Glauber Costa 47b075
+#endif
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+static unsigned int nacls = 0;
Glauber Costa 47b075
+static qemu_acl **acls = NULL;
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+qemu_acl *qemu_acl_find(const char *aclname)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    int i;
Glauber Costa 47b075
+    for (i = 0 ; i < nacls ; i++) {
Glauber Costa 47b075
+	if (strcmp(acls[i]->aclname, aclname) == 0)
Glauber Costa 47b075
+	    return acls[i];
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return NULL;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+qemu_acl *qemu_acl_init(const char *aclname)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    qemu_acl *acl;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    acl = qemu_acl_find(aclname);
Glauber Costa 47b075
+    if (acl)
Glauber Costa 47b075
+	return acl;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    acl = qemu_malloc(sizeof(*acl));
Glauber Costa 47b075
+    acl->aclname = qemu_strdup(aclname);
Glauber Costa 47b075
+    /* Deny by default, so there is no window of "open
Glauber Costa 47b075
+     * access" between QEMU starting, and the user setting
Glauber Costa 47b075
+     * up ACLs in the monitor */
Glauber Costa 47b075
+    acl->defaultDeny = 1;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    acl->nentries = 0;
Glauber Costa 47b075
+    TAILQ_INIT(&acl->entries);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1));
Glauber Costa 47b075
+    acls[nacls] = acl;
Glauber Costa 47b075
+    nacls++;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return acl;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+int qemu_acl_party_is_allowed(qemu_acl *acl,
Glauber Costa 47b075
+			      const char *party)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    qemu_acl_entry *entry;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    TAILQ_FOREACH(entry, &acl->entries, next) {
Glauber Costa 47b075
+#ifdef HAVE_FNMATCH_H
Glauber Costa 47b075
+	if (fnmatch(entry->match, party, 0) == 0)
Glauber Costa 47b075
+	    return entry->deny ? 0 : 1;
Glauber Costa 47b075
+#else
Glauber Costa 47b075
+	/* No fnmatch, so fallback to exact string matching
Glauber Costa 47b075
+	 * instead of allowing wildcards */
Glauber Costa 47b075
+	if (strcmp(entry->match, party) == 0)
Glauber Costa 47b075
+	    return entry->deny ? 0 : 1;
Glauber Costa 47b075
+#endif
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return acl->defaultDeny ? 0 : 1;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+void qemu_acl_reset(qemu_acl *acl)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    qemu_acl_entry *entry;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    /* Put back to deny by default, so there is no window
Glauber Costa 47b075
+     * of "open access" while the user re-initializes the
Glauber Costa 47b075
+     * access control list */
Glauber Costa 47b075
+    acl->defaultDeny = 1;
Glauber Costa 47b075
+    TAILQ_FOREACH(entry, &acl->entries, next) {
Glauber Costa 47b075
+	TAILQ_REMOVE(&acl->entries, entry, next);
Glauber Costa 47b075
+	free(entry->match);
Glauber Costa 47b075
+	free(entry);
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    acl->nentries = 0;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+int qemu_acl_append(qemu_acl *acl,
Glauber Costa 47b075
+		    int deny,
Glauber Costa 47b075
+		    const char *match)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    qemu_acl_entry *entry;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    entry = qemu_malloc(sizeof(*entry));
Glauber Costa 47b075
+    entry->match = qemu_strdup(match);
Glauber Costa 47b075
+    entry->deny = deny;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    TAILQ_INSERT_TAIL(&acl->entries, entry, next);
Glauber Costa 47b075
+    acl->nentries++;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return acl->nentries;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+int qemu_acl_insert(qemu_acl *acl,
Glauber Costa 47b075
+		    int deny,
Glauber Costa 47b075
+		    const char *match,
Glauber Costa 47b075
+		    int index)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    qemu_acl_entry *entry;
Glauber Costa 47b075
+    qemu_acl_entry *tmp;
Glauber Costa 47b075
+    int i = 0;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (index <= 0)
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+    if (index >= acl->nentries)
Glauber Costa 47b075
+	return qemu_acl_append(acl, deny, match);
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+    entry = qemu_malloc(sizeof(*entry));
Glauber Costa 47b075
+    entry->match = qemu_strdup(match);
Glauber Costa 47b075
+    entry->deny = deny;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    TAILQ_FOREACH(tmp, &acl->entries, next) {
Glauber Costa 47b075
+	i++;
Glauber Costa 47b075
+	if (i == index) {
Glauber Costa 47b075
+	    TAILQ_INSERT_BEFORE(tmp, entry, next);
Glauber Costa 47b075
+	    acl->nentries++;
Glauber Costa 47b075
+	    break;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return i;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+int qemu_acl_remove(qemu_acl *acl,
Glauber Costa 47b075
+		    const char *match)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    qemu_acl_entry *entry;
Glauber Costa 47b075
+    int i = 0;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    TAILQ_FOREACH(entry, &acl->entries, next) {
Glauber Costa 47b075
+	i++;
Glauber Costa 47b075
+	if (strcmp(entry->match, match) == 0) {
Glauber Costa 47b075
+	    TAILQ_REMOVE(&acl->entries, entry, next);
Glauber Costa 47b075
+	    return i;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    return -1;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * Local variables:
Glauber Costa 47b075
+ *  c-indent-level: 4
Glauber Costa 47b075
+ *  c-basic-offset: 4
Glauber Costa 47b075
+ *  tab-width: 8
Glauber Costa 47b075
+ * End:
Glauber Costa 47b075
+ */
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/acl.h
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- /dev/null
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/acl.h
Glauber Costa 47b075
@@ -0,0 +1,74 @@
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * QEMU access control list management
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Copyright (C) 2009 Red Hat, Inc
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Glauber Costa 47b075
+ * of this software and associated documentation files (the "Software"), to deal
Glauber Costa 47b075
+ * in the Software without restriction, including without limitation the rights
Glauber Costa 47b075
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Glauber Costa 47b075
+ * copies of the Software, and to permit persons to whom the Software is
Glauber Costa 47b075
+ * furnished to do so, subject to the following conditions:
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * The above copyright notice and this permission notice shall be included in
Glauber Costa 47b075
+ * all copies or substantial portions of the Software.
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Glauber Costa 47b075
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Glauber Costa 47b075
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Glauber Costa 47b075
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Glauber Costa 47b075
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Glauber Costa 47b075
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Glauber Costa 47b075
+ * THE SOFTWARE.
Glauber Costa 47b075
+ */
Glauber Costa 47b075
+
Glauber Costa 47b075
+#ifndef __QEMU_ACL_H__
Glauber Costa 47b075
+#define __QEMU_ACL_H__
Glauber Costa 47b075
+
Glauber Costa 47b075
+#include "sys-queue.h"
Glauber Costa 47b075
+
Glauber Costa 47b075
+typedef struct qemu_acl_entry qemu_acl_entry;
Glauber Costa 47b075
+typedef struct qemu_acl qemu_acl;
Glauber Costa 47b075
+
Glauber Costa 47b075
+struct qemu_acl_entry {
Glauber Costa 47b075
+    char *match;
Glauber Costa 47b075
+    int deny;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    TAILQ_ENTRY(qemu_acl_entry) next;
Glauber Costa 47b075
+};
Glauber Costa 47b075
+
Glauber Costa 47b075
+struct qemu_acl {
Glauber Costa 47b075
+    char *aclname;
Glauber Costa 47b075
+    unsigned int nentries;
Glauber Costa 47b075
+    TAILQ_HEAD(,qemu_acl_entry) entries;
Glauber Costa 47b075
+    int defaultDeny;
Glauber Costa 47b075
+};
Glauber Costa 47b075
+
Glauber Costa 47b075
+qemu_acl *qemu_acl_init(const char *aclname);
Glauber Costa 47b075
+
Glauber Costa 47b075
+qemu_acl *qemu_acl_find(const char *aclname);
Glauber Costa 47b075
+
Glauber Costa 47b075
+int qemu_acl_party_is_allowed(qemu_acl *acl,
Glauber Costa 47b075
+			      const char *party);
Glauber Costa 47b075
+
Glauber Costa 47b075
+void qemu_acl_reset(qemu_acl *acl);
Glauber Costa 47b075
+
Glauber Costa 47b075
+int qemu_acl_append(qemu_acl *acl,
Glauber Costa 47b075
+		    int deny,
Glauber Costa 47b075
+		    const char *match);
Glauber Costa 47b075
+int qemu_acl_insert(qemu_acl *acl,
Glauber Costa 47b075
+		    int deny,
Glauber Costa 47b075
+		    const char *match,
Glauber Costa 47b075
+		    int index);
Glauber Costa 47b075
+int qemu_acl_remove(qemu_acl *acl,
Glauber Costa 47b075
+		    const char *match);
Glauber Costa 47b075
+
Glauber Costa 47b075
+#endif /* __QEMU_ACL_H__ */
Glauber Costa 47b075
+
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * Local variables:
Glauber Costa 47b075
+ *  c-indent-level: 4
Glauber Costa 47b075
+ *  c-basic-offset: 4
Glauber Costa 47b075
+ *  tab-width: 8
Glauber Costa 47b075
+ * End:
Glauber Costa 47b075
+ */
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/configure
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/configure
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/configure
Glauber Costa 47b075
@@ -913,6 +913,21 @@ EOF
Glauber Costa 47b075
 fi
Glauber Costa 47b075
 
Glauber Costa 47b075
 ##########################################
Glauber Costa 47b075
+# fnmatch() probe, used for ACL routines
Glauber Costa 47b075
+fnmatch="no"
Glauber Costa 47b075
+cat > $TMPC << EOF
Glauber Costa 47b075
+#include <fnmatch.h>
Glauber Costa 47b075
+int main(void)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    fnmatch("foo", "foo", 0);
Glauber Costa 47b075
+    return 0;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+EOF
Glauber Costa 47b075
+if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then
Glauber Costa 47b075
+   fnmatch="yes"
Glauber Costa 47b075
+fi
Glauber Costa 47b075
+
Glauber Costa 47b075
+##########################################
Glauber Costa 47b075
 # vde libraries probe
Glauber Costa 47b075
 if test "$vde" = "yes" ; then
Glauber Costa 47b075
   cat > $TMPC << EOF
Glauber Costa 47b075
@@ -1501,6 +1516,9 @@ if test "$vnc_sasl" = "yes" ; then
Glauber Costa 47b075
   echo "CONFIG_VNC_SASL_LIBS=$vnc_sasl_libs" >> $config_mak
Glauber Costa 47b075
   echo "#define CONFIG_VNC_SASL 1" >> $config_h
Glauber Costa 47b075
 fi
Glauber Costa 47b075
+if test "$fnmatch" = "yes" ; then
Glauber Costa 47b075
+  echo "#define HAVE_FNMATCH_H 1" >> $config_h
Glauber Costa 47b075
+fi
Glauber Costa 47b075
 qemu_version=`head $source_path/VERSION`
Glauber Costa 47b075
 echo "VERSION=$qemu_version" >>$config_mak
Glauber Costa 47b075
 echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/monitor.c
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/monitor.c
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/monitor.c
Glauber Costa 47b075
@@ -39,6 +39,7 @@
Glauber Costa 47b075
 #include "qemu-timer.h"
Glauber Costa 47b075
 #include "migration.h"
Glauber Costa 47b075
 #include "kvm.h"
Glauber Costa 47b075
+#include "acl.h"
Glauber Costa 47b075
 
Glauber Costa 47b075
 #include "qemu-kvm.h"
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -1498,6 +1499,85 @@ static void do_info_balloon(void)
Glauber Costa 47b075
         term_printf("balloon: actual=%d\n", (int)(actual >> 20));
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
+static void do_acl(const char *command,
Glauber Costa 47b075
+		   const char *aclname,
Glauber Costa 47b075
+		   const char *match,
Glauber Costa 47b075
+		   int has_index,
Glauber Costa 47b075
+		   int index)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    qemu_acl *acl;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    acl = qemu_acl_find(aclname);
Glauber Costa 47b075
+    if (!acl) {
Glauber Costa 47b075
+	term_printf("acl: unknown list '%s'\n", aclname);
Glauber Costa 47b075
+	return;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (strcmp(command, "show") == 0) {
Glauber Costa 47b075
+	int i = 0;
Glauber Costa 47b075
+	qemu_acl_entry *entry;
Glauber Costa 47b075
+	term_printf("policy: %s\n",
Glauber Costa 47b075
+		    acl->defaultDeny ? "deny" : "allow");
Glauber Costa 47b075
+	TAILQ_FOREACH(entry, &acl->entries, next) {
Glauber Costa 47b075
+	    i++;
Glauber Costa 47b075
+	    term_printf("%d: %s %s\n", i,
Glauber Costa 47b075
+			entry->deny ? "deny" : "allow",
Glauber Costa 47b075
+			entry->match);
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    } else if (strcmp(command, "reset") == 0) {
Glauber Costa 47b075
+	qemu_acl_reset(acl);
Glauber Costa 47b075
+	term_printf("acl: removed all rules\n");
Glauber Costa 47b075
+    } else if (strcmp(command, "policy") == 0) {
Glauber Costa 47b075
+	if (!match) {
Glauber Costa 47b075
+	    term_printf("acl: missing policy parameter\n");
Glauber Costa 47b075
+	    return;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (strcmp(match, "allow") == 0) {
Glauber Costa 47b075
+	    acl->defaultDeny = 0;
Glauber Costa 47b075
+	    term_printf("acl: policy set to 'allow'\n");
Glauber Costa 47b075
+	} else if (strcmp(match, "deny") == 0) {
Glauber Costa 47b075
+	    acl->defaultDeny = 1;
Glauber Costa 47b075
+	    term_printf("acl: policy set to 'deny'\n");
Glauber Costa 47b075
+	} else {
Glauber Costa 47b075
+	    term_printf("acl: unknown policy '%s', expected 'deny' or 'allow'\n", match);
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    } else if ((strcmp(command, "allow") == 0) ||
Glauber Costa 47b075
+	       (strcmp(command, "deny") == 0)) {
Glauber Costa 47b075
+	int deny = strcmp(command, "deny") == 0 ? 1 : 0;
Glauber Costa 47b075
+	int ret;
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (!match) {
Glauber Costa 47b075
+	    term_printf("acl: missing match parameter\n");
Glauber Costa 47b075
+	    return;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (has_index)
Glauber Costa 47b075
+	    ret = qemu_acl_insert(acl, deny, match, index);
Glauber Costa 47b075
+	else
Glauber Costa 47b075
+	    ret = qemu_acl_append(acl, deny, match);
Glauber Costa 47b075
+	if (ret < 0)
Glauber Costa 47b075
+	    term_printf("acl: unable to add acl entry\n");
Glauber Costa 47b075
+	else
Glauber Costa 47b075
+	    term_printf("acl: added rule at position %d\n", ret);
Glauber Costa 47b075
+    } else if (strcmp(command, "remove") == 0) {
Glauber Costa 47b075
+	int ret;
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (!match) {
Glauber Costa 47b075
+	    term_printf("acl: missing match parameter\n");
Glauber Costa 47b075
+	    return;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	ret = qemu_acl_remove(acl, match);
Glauber Costa 47b075
+	if (ret < 0)
Glauber Costa 47b075
+	    term_printf("acl: no matching acl entry\n");
Glauber Costa 47b075
+	else
Glauber Costa 47b075
+	    term_printf("acl: removed rule at position %d\n", ret);
Glauber Costa 47b075
+    } else {
Glauber Costa 47b075
+	term_printf("acl: unknown command '%s'\n", command);
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
 /* Please update qemu-doc.texi when adding or changing commands */
Glauber Costa 47b075
 static const term_cmd_t term_cmds[] = {
Glauber Costa 47b075
     { "help|?", "s?", do_help,
Glauber Costa 47b075
@@ -1603,6 +1683,12 @@ static const term_cmd_t term_cmds[] = {
Glauber Costa 47b075
     { "set_link", "ss", do_set_link,
Glauber Costa 47b075
       "name [up|down]", "change the link status of a network adapter" },
Glauber Costa 47b075
     { "set_link", "ss", do_set_link, "name [up|down]" },
Glauber Costa 47b075
+    { "acl", "sss?i?", do_acl, "<command> <aclname> [<match>] [<index>]\n",
Glauber Costa 47b075
+                                "acl show vnc.username\n"
Glauber Costa 47b075
+                                "acl policy vnc.username deny\n"
Glauber Costa 47b075
+                                "acl allow vnc.username fred\n"
Glauber Costa 47b075
+                                "acl deny vnc.username bob\n"
Glauber Costa 47b075
+                                "acl reset vnc.username\n" },
Glauber Costa 47b075
     { "cpu_set", "is", do_cpu_set_nr, "cpu [online|offline]", "change cpu state" },
Glauber Costa 47b075
 #if defined(TARGET_I386) || defined(TARGET_X86_64)
Glauber Costa 47b075
     { "drive_add", "iss", drive_hot_add, "pcibus pcidevfn [file=file][,if=type][,bus=n]\n"
Glauber Costa 47b075
@@ -1611,6 +1697,7 @@ static const term_cmd_t term_cmds[] = {
Glauber Costa 47b075
                                         "[snapshot=on|off][,cache=on|off]",
Glauber Costa 47b075
                                         "add drive to PCI storage controller" },
Glauber Costa 47b075
 #endif
Glauber Costa 47b075
+
Glauber Costa 47b075
     { NULL, NULL, },
Glauber Costa 47b075
 };
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -2995,3 +3082,12 @@ int monitor_read_bdrv_key(BlockDriverSta
Glauber Costa 47b075
     }
Glauber Costa 47b075
     return -EPERM;
Glauber Costa 47b075
 }
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * Local variables:
Glauber Costa 47b075
+ *  c-indent-level: 4
Glauber Costa 47b075
+ *  c-basic-offset: 4
Glauber Costa 47b075
+ *  tab-width: 8
Glauber Costa 47b075
+ * End:
Glauber Costa 47b075
+ */
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/qemu-doc.texi
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/qemu-doc.texi
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/qemu-doc.texi
Glauber Costa 47b075
@@ -639,6 +639,19 @@ ensures a data encryption preventing com
Glauber Costa 47b075
 credentials. See the @ref{vnc_security} section for details on using
Glauber Costa 47b075
 SASL authentication.
Glauber Costa 47b075
 
Glauber Costa 47b075
+@item acl
Glauber Costa 47b075
+
Glauber Costa 47b075
+Turn on access control lists for checking of the x509 client certificate
Glauber Costa 47b075
+and SASL party. For x509 certs, the ACL check is made against the
Glauber Costa 47b075
+certificate's distinguished name. This is something that looks like
Glauber Costa 47b075
+@code{C=GB,O=ACME,L=Boston,CN=bob}. For SASL party, the ACL check is
Glauber Costa 47b075
+made against the username, which depending on the SASL plugin, may
Glauber Costa 47b075
+include a realm component, eg @code{bob} or @code{bob\@EXAMPLE.COM}.
Glauber Costa 47b075
+When the @option{acl} flag is set, the initial access list will be
Glauber Costa 47b075
+empty, with a @code{deny} policy. Thus no one will be allowed to
Glauber Costa 47b075
+use the VNC server until the ACLs have been loaded. This can be
Glauber Costa 47b075
+achieved using the @code{acl} monitor command.
Glauber Costa 47b075
+
Glauber Costa 47b075
 @end table
Glauber Costa 47b075
 
Glauber Costa 47b075
 @end table
Glauber Costa 47b075
@@ -1400,6 +1413,42 @@ Password: ********
Glauber Costa 47b075
 
Glauber Costa 47b075
 @end table
Glauber Costa 47b075
 
Glauber Costa 47b075
+@item acl @var{subcommand} @var{aclname} @var{match} @var{index}
Glauber Costa 47b075
+
Glauber Costa 47b075
+Manage access control lists for network services. There are currently
Glauber Costa 47b075
+two named access control lists, @var{vnc.x509dname} and @var{vnc.username}
Glauber Costa 47b075
+matching on the x509 client certificate distinguished name, and SASL
Glauber Costa 47b075
+username respectively.
Glauber Costa 47b075
+
Glauber Costa 47b075
+@table @option
Glauber Costa 47b075
+@item acl show <aclname>
Glauber Costa 47b075
+list all the match rules in the access control list, and the default
Glauber Costa 47b075
+policy
Glauber Costa 47b075
+@item acl policy <aclname> @code{allow|deny}
Glauber Costa 47b075
+set the default access control list policy, used in the event that
Glauber Costa 47b075
+none of the explicit rules match. The default policy at startup is
Glauber Costa 47b075
+always @code{deny}
Glauber Costa 47b075
+@item acl allow <aclname> <match> [<index>]
Glauber Costa 47b075
+add a match to the access control list, allowing access. The match will
Glauber Costa 47b075
+normally be an exact username or x509 distinguished name, but can
Glauber Costa 47b075
+optionally include wildcard globs. eg @code{*\@EXAMPLE.COM} to allow
Glauber Costa 47b075
+all users in the @code{EXAMPLE.COM} kerberos realm. The match will
Glauber Costa 47b075
+normally be appended to the end of the ACL, but can be inserted
Glauber Costa 47b075
+earlier in the list if the optional @code{index} parameter is supplied.
Glauber Costa 47b075
+@item acl deny <aclname> <match> [<index>]
Glauber Costa 47b075
+add a match to the access control list, denying access. The match will
Glauber Costa 47b075
+normally be an exact username or x509 distinguished name, but can
Glauber Costa 47b075
+optionally include wildcard globs. eg @code{*\@EXAMPLE.COM} to allow
Glauber Costa 47b075
+all users in the @code{EXAMPLE.COM} kerberos realm. The match will
Glauber Costa 47b075
+normally be appended to the end of the ACL, but can be inserted
Glauber Costa 47b075
+earlier in the list if the optional @code{index} parameter is supplied.
Glauber Costa 47b075
+@item acl remove <aclname> <match>
Glauber Costa 47b075
+remove the specified match rule from the access control list.
Glauber Costa 47b075
+@item acl reset <aclname>
Glauber Costa 47b075
+remove all matches from the access control list, and set the default
Glauber Costa 47b075
+policy back to @code{deny}.
Glauber Costa 47b075
+@end table
Glauber Costa 47b075
+
Glauber Costa 47b075
 @item screendump @var{filename}
Glauber Costa 47b075
 Save screen into PPM image @var{filename}.
Glauber Costa 47b075
 
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc-auth-sasl.c
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/vnc-auth-sasl.c
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc-auth-sasl.c
Glauber Costa 47b075
@@ -120,22 +120,32 @@ static int vnc_auth_sasl_check_access(Vn
Glauber Costa 47b075
 {
Glauber Costa 47b075
     const void *val;
Glauber Costa 47b075
     int err;
Glauber Costa 47b075
+    int allow;
Glauber Costa 47b075
 
Glauber Costa 47b075
     err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val;;
Glauber Costa 47b075
     if (err != SASL_OK) {
Glauber Costa 47b075
-	VNC_DEBUG("cannot query SASL username on connection %d (%s)\n",
Glauber Costa 47b075
+	VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n",
Glauber Costa 47b075
 		  err, sasl_errstring(err, NULL, NULL));
Glauber Costa 47b075
 	return -1;
Glauber Costa 47b075
     }
Glauber Costa 47b075
     if (val == NULL) {
Glauber Costa 47b075
-	VNC_DEBUG("no client username was found\n");
Glauber Costa 47b075
+	VNC_DEBUG("no client username was found, denying access\n");
Glauber Costa 47b075
 	return -1;
Glauber Costa 47b075
     }
Glauber Costa 47b075
     VNC_DEBUG("SASL client username %s\n", (const char *)val);
Glauber Costa 47b075
 
Glauber Costa 47b075
     vs->sasl.username = qemu_strdup((const char*)val);
Glauber Costa 47b075
 
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
+    if (vs->vd->sasl.acl == NULL) {
Glauber Costa 47b075
+	VNC_DEBUG("no ACL activated, allowing access\n");
Glauber Costa 47b075
+	return 0;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username,
Glauber Costa 47b075
+	      allow ? "allowed" : "denied");
Glauber Costa 47b075
+    return allow ? 0 : -1;
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
 static int vnc_auth_sasl_check_ssf(VncState *vs)
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc-auth-sasl.h
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/vnc-auth-sasl.h
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc-auth-sasl.h
Glauber Costa 47b075
@@ -30,6 +30,9 @@
Glauber Costa 47b075
 #include <sasl/sasl.h>
Glauber Costa 47b075
 
Glauber Costa 47b075
 typedef struct VncStateSASL VncStateSASL;
Glauber Costa 47b075
+typedef struct VncDisplaySASL VncDisplaySASL;
Glauber Costa 47b075
+
Glauber Costa 47b075
+#include "acl.h"
Glauber Costa 47b075
 
Glauber Costa 47b075
 struct VncStateSASL {
Glauber Costa 47b075
     sasl_conn_t *conn;
Glauber Costa 47b075
@@ -56,6 +59,10 @@ struct VncStateSASL {
Glauber Costa 47b075
     char *mechlist;
Glauber Costa 47b075
 };
Glauber Costa 47b075
 
Glauber Costa 47b075
+struct VncDisplaySASL {
Glauber Costa 47b075
+    qemu_acl *acl;
Glauber Costa 47b075
+};
Glauber Costa 47b075
+
Glauber Costa 47b075
 void vnc_sasl_client_cleanup(VncState *vs);
Glauber Costa 47b075
 
Glauber Costa 47b075
 long vnc_client_read_sasl(VncState *vs);
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc-tls.c
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/vnc-tls.c
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc-tls.c
Glauber Costa 47b075
@@ -255,6 +255,25 @@ int vnc_tls_validate_certificate(struct 
Glauber Costa 47b075
 			  gnutls_strerror (ret));
Glauber Costa 47b075
 		return -1;
Glauber Costa 47b075
 	    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+	    if (vs->vd->tls.x509verify) {
Glauber Costa 47b075
+		int allow;
Glauber Costa 47b075
+		if (!vs->vd->tls.acl) {
Glauber Costa 47b075
+		    VNC_DEBUG("no ACL activated, allowing access");
Glauber Costa 47b075
+		    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
+		    continue;
Glauber Costa 47b075
+		}
Glauber Costa 47b075
+
Glauber Costa 47b075
+		allow = qemu_acl_party_is_allowed(vs->vd->tls.acl,
Glauber Costa 47b075
+						  vs->tls.dname);
Glauber Costa 47b075
+
Glauber Costa 47b075
+		VNC_DEBUG("TLS x509 ACL check for %s is %s\n",
Glauber Costa 47b075
+			  vs->tls.dname, allow ? "allowed" : "denied");
Glauber Costa 47b075
+		if (!allow) {
Glauber Costa 47b075
+		    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
+		    return -1;
Glauber Costa 47b075
+		}
Glauber Costa 47b075
+	    }
Glauber Costa 47b075
 	}
Glauber Costa 47b075
 
Glauber Costa 47b075
 	gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc-tls.h
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/vnc-tls.h
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc-tls.h
Glauber Costa 47b075
@@ -31,6 +31,8 @@
Glauber Costa 47b075
 #include <gnutls/gnutls.h>
Glauber Costa 47b075
 #include <gnutls/x509.h>
Glauber Costa 47b075
 
Glauber Costa 47b075
+#include "acl.h"
Glauber Costa 47b075
+
Glauber Costa 47b075
 enum {
Glauber Costa 47b075
     VNC_WIREMODE_CLEAR,
Glauber Costa 47b075
     VNC_WIREMODE_TLS,
Glauber Costa 47b075
@@ -42,6 +44,7 @@ typedef struct VncStateTLS VncStateTLS;
Glauber Costa 47b075
 /* Server state */
Glauber Costa 47b075
 struct VncDisplayTLS {
Glauber Costa 47b075
     int x509verify; /* Non-zero if server requests & validates client cert */
Glauber Costa 47b075
+    qemu_acl *acl;
Glauber Costa 47b075
 
Glauber Costa 47b075
     /* Paths to x509 certs/keys */
Glauber Costa 47b075
     char *x509cacert;
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc.c
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/vnc.c
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc.c
Glauber Costa 47b075
@@ -28,6 +28,7 @@
Glauber Costa 47b075
 #include "sysemu.h"
Glauber Costa 47b075
 #include "qemu_socket.h"
Glauber Costa 47b075
 #include "qemu-timer.h"
Glauber Costa 47b075
+#include "acl.h"
Glauber Costa 47b075
 
Glauber Costa 47b075
 #define VNC_REFRESH_INTERVAL (1000 / 30)
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -2082,6 +2083,7 @@ int vnc_display_open(DisplayState *ds, c
Glauber Costa 47b075
     int sasl = 0;
Glauber Costa 47b075
     int saslErr;
Glauber Costa 47b075
 #endif
Glauber Costa 47b075
+    int acl = 0;
Glauber Costa 47b075
 
Glauber Costa 47b075
     if (!vnc_display)
Glauber Costa 47b075
         return -1;
Glauber Costa 47b075
@@ -2138,9 +2140,28 @@ int vnc_display_open(DisplayState *ds, c
Glauber Costa 47b075
 		return -1;
Glauber Costa 47b075
 	    }
Glauber Costa 47b075
 #endif
Glauber Costa 47b075
+	} else if (strncmp(options, "acl", 3) == 0) {
Glauber Costa 47b075
+	    acl = 1;
Glauber Costa 47b075
 	}
Glauber Costa 47b075
     }
Glauber Costa 47b075
 
Glauber Costa 47b075
+#ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
+    if (acl && x509 && vs->tls.x509verify) {
Glauber Costa 47b075
+	if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
Glauber Costa 47b075
+	    fprintf(stderr, "Failed to create x509 dname ACL\n");
Glauber Costa 47b075
+	    exit(1);
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+#endif
Glauber Costa 47b075
+#ifdef CONFIG_VNC_SASL
Glauber Costa 47b075
+    if (acl && sasl) {
Glauber Costa 47b075
+	if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
Glauber Costa 47b075
+	    fprintf(stderr, "Failed to create username ACL\n");
Glauber Costa 47b075
+	    exit(1);
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+#endif
Glauber Costa 47b075
+
Glauber Costa 47b075
     /*
Glauber Costa 47b075
      * Combinations we support here:
Glauber Costa 47b075
      *
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc.h
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/vnc.h
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc.h
Glauber Costa 47b075
@@ -98,6 +98,9 @@ struct VncDisplay
Glauber Costa 47b075
     int subauth; /* Used by VeNCrypt */
Glauber Costa 47b075
     VncDisplayTLS tls;
Glauber Costa 47b075
 #endif
Glauber Costa 47b075
+#ifdef CONFIG_VNC_SASL
Glauber Costa 47b075
+    VncDisplaySASL sasl;
Glauber Costa 47b075
+#endif
Glauber Costa 47b075
 };
Glauber Costa 47b075
 
Glauber Costa 47b075
 struct VncState