From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LXd7V-0004eu-2w for qemu-devel@nongnu.org; Thu, 12 Feb 2009 10:04:53 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LXd7U-0004eH-1J for qemu-devel@nongnu.org; Thu, 12 Feb 2009 10:04:52 -0500 Received: from [199.232.76.173] (port=37795 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LXd7T-0004eE-U1 for qemu-devel@nongnu.org; Thu, 12 Feb 2009 10:04:51 -0500 Received: from mx1.redhat.com ([66.187.233.31]:38463) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LXd7T-0007P2-DQ for qemu-devel@nongnu.org; Thu, 12 Feb 2009 10:04:51 -0500 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id n1CF4pCJ026422 for ; Thu, 12 Feb 2009 10:04:51 -0500 Received: from file.fab.redhat.com (file.fab.redhat.com [10.33.63.6]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n1CF4q6x025949 for ; Thu, 12 Feb 2009 10:04:53 -0500 Received: from file.fab.redhat.com (localhost.localdomain [127.0.0.1]) by file.fab.redhat.com (8.13.1/8.13.1) with ESMTP id n1CF4nIQ029677 for ; Thu, 12 Feb 2009 15:04:49 GMT Received: (from berrange@localhost) by file.fab.redhat.com (8.13.1/8.13.1/Submit) id n1CF4n5R029673 for qemu-devel@nongnu.org; Thu, 12 Feb 2009 15:04:49 GMT Date: Thu, 12 Feb 2009 15:04:49 +0000 From: "Daniel P. Berrange" Subject: Re: [Qemu-devel] PATCH: 7/7: Add external persistent ACL file Message-ID: <20090212150449.GW9894@redhat.com> References: <20090212145302.GO9894@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20090212145302.GO9894@redhat.com> Reply-To: "Daniel P. Berrange" , qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 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 #include @@ -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 :|