qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] PATCH: 7/7: Add external persistent ACL file


From: Daniel P. Berrange
Subject: Re: [Qemu-devel] PATCH: 7/7: Add external persistent ACL file
Date: Thu, 12 Feb 2009 15:04:49 +0000
User-agent: Mutt/1.4.1i

This patch introduces a simple access control file capability
for authorizing clients of QEMU's various network services.
The file is designed such that it can be shared amongst multiple
QEMU instances. The style of commands is similar to that used
in the monitor ACL commands. It is a line oriented format, with
comments indicated by leading '#'.Each non-comment line consists
of 4 fields, 'scope', 'aclname', 'action' and 'value'.

The scope allows control over what VMs the rule applies to. This
is a glob, so '*' matches any VM. An explicit value can be match
against the VM name, as given by the '-name' argument.

The aclname is one of the ACLs defined by QEMU, either vnc.username
or vnc.x509dname for now. More later perhaps.

The action can be one of 'policy' 'allow', or 'deny'. The policy
sets the default allow/deny state for the ACL, if no rules match.

Finally the 'value' is another glob matching against the client
name being checked.

An example showing use of both SASL username ACLs, and x509 client
certificate distinguished name ACLs.

   # Default deny all for all SASL authenticated users in all VMs
   * vnc.username policy deny

   # Allow bob access to all VMs
   * vnc.username allow bob

   # Allow fred and test access to the VM named 'demo'
   demo vnc.username allow fred
   demo vnc.username allow test


   # Deny all x509 client certificates on all VMs
   * vnc.x509dname policy deny

   # Allow all users from the ACME, London office to all VMs
   * vnc.x509dname allow "C=GB,O=ACME,L=London,CN=*"

   # Allow Joe from Boston, access to VM 'demo'
   demo vnc.x509dname allow "C=GB,O=ACME,L=Boston,CN=joe"


Save this to a file, and give it to QEMU at startup with '-acl demo.acl'

The code for parsing the file is a little crude because I didn't want
to spend too much time writing this. Its more of a proof of concept
of how it might be possible to store ACL rules in a simple way.


   Signed-off-by: Daniel P. Berrange <address@hidden>



 acl.c |  106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 acl.h |    3 +
 vl.c  |   12 +++++++
 3 files changed, 121 insertions(+)

Daniel

diff -r 2914a8816f5a acl.c
--- a/acl.c     Thu Feb 12 12:48:44 2009 +0000
+++ b/acl.c     Thu Feb 12 12:48:48 2009 +0000
@@ -71,6 +71,112 @@ ACL *qemu_acl_init(const char *aclname)
     return acl;
 }
 
+#define SKIP_SPACES(buf) while (*buf == ' ') { buf++; }
+
+int qemu_acl_load_file(const char *path,
+                      const char *name)
+{
+    FILE *f = fopen(path, "r");
+    char line[1024];
+    int ret = -1;
+    int linenum = 0;
+
+    if (!f)
+       return -1;
+
+    /* *       vnc.username policy deny */
+    /* *       vnc.username allow  fred */
+    /* somevm  vnc.username allow  joe */
+    /* somevm  vnc.username deny   bob*/
+    while (fgets(line, sizeof(line), f)) {
+       char *scope, *aclname, *action, *value;
+       char *tmp = line;
+       ACL *acl;
+       int quoted = 0;
+
+       linenum++;
+
+       SKIP_SPACES(tmp);
+       if (line[0] == '#' ||
+           line[0] == '\n' ||
+           line[0] == '\0')
+           continue;
+
+       scope = tmp;
+
+       tmp = strchr(tmp, ' ');
+       if (!tmp) {
+           fprintf(stderr, "missing aclname data at line %d\n", linenum);
+           continue;
+       }
+       *tmp++ = '\0';
+       SKIP_SPACES(tmp);
+       aclname = tmp;
+
+       tmp = strchr(tmp, ' ');
+       if (!tmp) {
+           fprintf(stderr, "missing action data at line %d\n", linenum);
+           continue;
+       }
+       *tmp++ = '\0';
+       SKIP_SPACES(tmp);
+       action = tmp;
+
+       tmp = strchr(tmp, ' ');
+       if (!tmp) {
+           fprintf(stderr, "missing value data at line %d\n", linenum);
+           continue;
+       }
+       *tmp++ = '\0';
+       SKIP_SPACES(tmp);
+       value = tmp;
+
+
+       if (*tmp == '"') {
+           quoted = 1;
+           value++;
+           tmp++;
+       }
+       while (*tmp != '\0' && *tmp != '\n') {
+           if ((quoted && *tmp == '"') ||
+               (!quoted && *tmp == ' '))
+                   break;
+           tmp++;
+       }
+       if (tmp)
+           *tmp = '\0';
+
+       if (fnmatch(scope, name ? name : "", 0) != 0) {
+           continue;
+       }
+
+       acl = qemu_acl_init(aclname);
+       if (!acl)
+           goto cleanup;
+
+       if (strcmp(action, "policy") == 0) {
+           if (strcmp(value, "allow") == 0)
+               acl->defaultDeny = 0;
+           else if (strcmp(value, "deny") == 0)
+               acl->defaultDeny = 1;
+           else
+               fprintf(stderr, "unknown ACL policy '%s'\n", value);
+       } else if (strcmp(action, "allow") == 0 ||
+                  strcmp(action, "deny") == 0) {
+           int deny = strcmp(action, "deny") == 0 ? 1 : 0;
+           qemu_acl_append(acl, deny, value);
+       } else {
+           fprintf(stderr, "unknown ACL action '%s'\n", action);
+       }
+    }
+    ret = 0;
+
+ cleanup:
+    fclose(f);
+
+    return ret;
+}
+
 int qemu_acl_party_is_allowed(ACL *acl,
                              const char *party)
 {
diff -r 2914a8816f5a acl.h
--- a/acl.h     Thu Feb 12 12:48:44 2009 +0000
+++ b/acl.h     Thu Feb 12 12:48:48 2009 +0000
@@ -44,6 +44,9 @@ ACL *qemu_acl_init(const char *aclname);
 
 ACL *qemu_acl_find(const char *aclname);
 
+int qemu_acl_load_file(const char *path,
+                      const char *name);
+
 int qemu_acl_party_is_allowed(ACL *acl,
                              const char *party);
 
diff -r 2914a8816f5a vl.c
--- a/vl.c      Thu Feb 12 12:48:44 2009 +0000
+++ b/vl.c      Thu Feb 12 12:48:48 2009 +0000
@@ -42,6 +42,7 @@
 #include "migration.h"
 #include "kvm.h"
 #include "balloon.h"
+#include "acl.h"
 
 #include <unistd.h>
 #include <fcntl.h>
@@ -3948,6 +3949,7 @@ static void help(int exitcode)
            "-g WxH[xDEPTH]  Set the initial graphical resolution and depth\n"
 #endif
            "-vnc display    start a VNC server on display\n"
+           "-acl path       path to access control list for network services\n"
            "\n"
            "Network options:\n"
            "-net nic[,vlan=n][,macaddr=addr][,model=type][,name=str]\n"
@@ -4129,6 +4131,7 @@ enum {
     QEMU_OPTION_full_screen,
     QEMU_OPTION_g,
     QEMU_OPTION_vnc,
+    QEMU_OPTION_acl,
 
     /* Network options: */
     QEMU_OPTION_net,
@@ -4243,6 +4246,7 @@ static const QEMUOption qemu_options[] =
     { "g", 1, QEMU_OPTION_g },
 #endif
     { "vnc", HAS_ARG, QEMU_OPTION_vnc },
+    { "acl", HAS_ARG, QEMU_OPTION_acl },
 
     /* Network options: */
     { "net", HAS_ARG, QEMU_OPTION_net},
@@ -4621,6 +4625,7 @@ int main(int argc, char **argv, char **e
     const char *pid_file = NULL;
     int autostart;
     const char *incoming = NULL;
+    const char *acl_file = NULL;
 
     qemu_cache_utils_init(envp);
 
@@ -5160,6 +5165,9 @@ int main(int argc, char **argv, char **e
            case QEMU_OPTION_vnc:
                vnc_display = optarg;
                break;
+           case QEMU_OPTION_acl:
+               acl_file = optarg;
+               break;
             case QEMU_OPTION_no_acpi:
                 acpi_enabled = 0;
                 break;
@@ -5611,6 +5619,10 @@ int main(int argc, char **argv, char **e
         }
     }
 
+    /* Load access control data */
+    if (acl_file)
+       qemu_acl_load_file(acl_file, qemu_name);
+
     if (!display_state)
         dumb_display_init();
     /* just use the first displaystate for the moment */

-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




reply via email to

[Prev in Thread] Current Thread [Next in Thread]