SECURITY_DRIVER_APPARMOR_SOURCES = \
security/security_apparmor.h security/security_apparmor.c
+ACCESS_DRIVER_GENERATED = \
+ access/viraccessapicheck.h access/viraccessapicheck.c \
+ access/viraccessapicheckqemu.h access/viraccessapicheckqemu.c \
+ access/viraccessapichecklxc.h access/viraccessapichecklxc.c
+
+ACCESS_DRIVER_SYMFILES = \
+ libvirt_access.syms \
+ libvirt_access_qemu.syms \
+ libvirt_access_lxc.syms
ACCESS_DRIVER_SOURCES = \
access/viraccessperm.h access/viraccessperm.c \
libvirt_security_manager_la_CFLAGS += $(APPARMOR_CFLAGS)
endif
-libvirt_driver_access_la_SOURCES = $(ACCESS_DRIVER_SOURCES)
+libvirt_driver_access_la_SOURCES = $(ACCESS_DRIVER_SOURCES) $(ACCESS_DRIVER_GENERATED)
noinst_LTLIBRARIES += libvirt_driver_access.la
libvirt_la_BUILT_LIBADD += libvirt_driver_access.la
libvirt_driver_access_la_CFLAGS = \
endif
+USED_SYM_FILES += $(ACCESS_DRIVER_SYMFILES)
+BUILT_SOURCES += $(ACCESS_DRIVER_GENERATED) $(ACCESS_DRIVER_SYMFILES)
+CLEANFILES += $(ACCESS_DRIVER_GENERATED) $(ACCESS_DRIVER_SYMFILES)
+
+libvirt_access.syms: $(srcdir)/rpc/gendispatch.pl \
+ $(REMOTE_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclsym \
+ remote REMOTE $(REMOTE_PROTOCOL) > $@
+libvirt_access_qemu.syms: $(srcdir)/rpc/gendispatch.pl \
+ $(QEMU_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclsym \
+ qemu QEMU $(QEMU_PROTOCOL) > $@
+libvirt_access_lxc.syms: $(srcdir)/rpc/gendispatch.pl \
+ $(LXC_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclsym \
+ lxc LXC $(LXC_PROTOCOL) > $@
+
+access/viraccessapicheck.h: $(srcdir)/rpc/gendispatch.pl \
+ $(REMOTE_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclheader \
+ remote REMOTE $(REMOTE_PROTOCOL) > $@
+access/viraccessapicheck.c: $(srcdir)/rpc/gendispatch.pl \
+ $(REMOTE_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclbody \
+ remote REMOTE $(REMOTE_PROTOCOL) access/viraccessapicheck.h > $@
+
+access/viraccessapicheckqemu.h: $(srcdir)/rpc/gendispatch.pl \
+ $(QEMU_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclheader \
+ qemu QEMU $(QEMU_PROTOCOL) > $@
+access/viraccessapicheckqemu.c: $(srcdir)/rpc/gendispatch.pl \
+ $(QEMU_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclbody \
+ qemu QEMU $(QEMU_PROTOCOL) access/viraccessapicheckqemu.h > $@
+
+access/viraccessapichecklxc.h: $(srcdir)/rpc/gendispatch.pl \
+ $(LXC_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclheader \
+ lxc LXC $(LXC_PROTOCOL) > $@
+access/viraccessapichecklxc.c: $(srcdir)/rpc/gendispatch.pl \
+ $(LXC_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=aclbody \
+ lxc LXC $(LXC_PROTOCOL) access/viraccessapichecklxc.h > $@
+
# Add all conditional sources just in case...
EXTRA_DIST += \
$(TEST_DRIVER_SOURCES) \
die "cannot parse command line options" unless $res;
-die "unknown mode '$mode', expecting 'client', 'server' or 'debug'"
- unless $mode =~ /^(client|server|debug)$/;
+die "unknown mode '$mode', expecting 'client', 'server', " .
+ "'aclheader', 'aclbody', 'aclsym' or 'debug'"
+ unless $mode =~ /^(client|server|aclheader|aclbody|aclsym|debug)$/;
my $structprefix = shift or die "missing struct prefix argument";
my $procprefix = shift or die "missing procedure prefix argument";
}
} elsif ($collect_opts) {
if (m,^\s*\*\s*\@(\w+)\s*:\s*((?:\w|:|\!|\|)+)\s*$,) {
- $opts{$1} = $2;
+ if ($1 eq "acl" ||
+ $1 eq "aclfilter") {
+ $opts{$1} = [] unless exists $opts{$1};
+ push @{$opts{$1}}, $2;
+ } else {
+ $opts{$1} = $2;
+ }
} elsif (m,^\s*\*/\s*$,) {
$collect_opts = 0;
} elsif (m,^\s*\*\s*$,) {
$calls{$name}->{streamflag} = "none";
}
+ $calls{$name}->{acl} = $opts{acl};
+ $calls{$name}->{aclfilter} = $opts{aclfilter};
# for now, we distinguish only two levels of priority:
# low (0) and high (1)
#----------------------------------------------------------------------
# Output
-print <<__EOF__;
+if ($mode eq "aclsym") {
+ print <<__EOF__;
+# Automatically generated by gendispatch.pl.
+# Do not edit this file. Any changes you make will be lost.
+__EOF__
+} else {
+ print <<__EOF__;
/* Automatically generated by gendispatch.pl.
* Do not edit this file. Any changes you make will be lost.
*/
__EOF__
+}
# Debugging.
if ($mode eq "debug") {
print " return rv;\n";
print "}\n";
}
+} elsif ($mode eq "aclheader" ||
+ $mode eq "aclbody" ||
+ $mode eq "aclsym") {
+ my %generate = map { $_ => 1 } @autogen;
+ my @keys = keys %calls;
+
+ if ($mode eq "aclsym") {
+ @keys = sort { my $c = $a . "ensureacl";
+ my $d = $b . "ensureacl";
+ $c cmp $d } @keys;
+ } else {
+ @keys = sort { $a cmp $b } @keys;
+ }
+
+ if ($mode eq "aclheader") {
+ my @headers = (
+ "internal.h",
+ "domain_conf.h",
+ "network_conf.h",
+ "secret_conf.h",
+ "storage_conf.h",
+ "nwfilter_conf.h",
+ "node_device_conf.h",
+ "interface_conf.h"
+ );
+ foreach my $hdr (@headers) {
+ print "#include \"$hdr\"\n";
+ }
+ } elsif ($mode eq "aclbody") {
+ my $header = shift;
+ print "#include <config.h>\n";
+ print "#include \"$header\"\n";
+ print "#include \"access/viraccessmanager.h\"\n";
+ print "#include \"datatypes.h\"\n";
+ print "#include \"virerror.h\"\n";
+ print "\n";
+ print "#define VIR_FROM_THIS VIR_FROM_ACCESS\n";
+ }
+ print "\n";
+
+ foreach (@keys) {
+ my $call = $calls{$_};
+
+ die "missing 'acl' option for $call->{ProcName}"
+ unless exists $call->{acl} &&
+ $#{$call->{acl}} != -1;
+
+ next if $call->{acl}->[0] eq "none";
+
+ if ($mode eq "aclsym") {
+ my $apiname = "vir" . $call->{ProcName};
+ if ($structprefix eq "qemu") {
+ $apiname =~ s/virDomain/virDomainQemu/;
+ } elsif ($structprefix eq "lxc") {
+ $apiname =~ s/virDomain/virDomainLxc/;
+ }
+ if (defined $call->{aclfilter}) {
+ print $apiname . "CheckACL;\n";
+ }
+ print $apiname . "EnsureACL;\n";
+ } else {
+ &generate_acl($call, $call->{acl}, "Ensure");
+ if (defined $call->{aclfilter}) {
+ &generate_acl($call, $call->{aclfilter}, "Check");
+ }
+ }
+
+ sub generate_acl {
+ my $call = shift;
+ my $acl = shift;
+ my $action = shift;
+
+ my @acl;
+ foreach (@{$acl}) {
+ my @bits = split /:/;
+ push @acl, { object => $bits[0], perm => $bits[1], flags => $bits[2] }
+ }
+
+ my $checkflags = 0;
+ for (my $i = 1 ; $i <= $#acl ; $i++) {
+ if ($acl[$i]->{object} ne $acl[0]->{object}) {
+ die "acl for '$call->{ProcName}' cannot check different objects";
+ }
+ if (defined $acl[$i]->{flags}) {
+ $checkflags = 1;
+ }
+ }
+
+ my $apiname = "vir" . $call->{ProcName};
+ if ($structprefix eq "qemu") {
+ $apiname =~ s/virDomain/virDomainQemu/;
+ } elsif ($structprefix eq "lxc") {
+ $apiname =~ s/virDomain/virDomainLxc/;
+ }
+
+ my $object = $acl[0]->{object};
+ my $arg = $acl[0]->{object};
+ $arg =~ s/^.*_(\w+)$/$1/;
+ $object =~ s/^(\w)/uc $1/e;
+ $object =~ s/_(\w)/uc $1/e;
+ $object =~ s/Nwfilter/NWFilter/;
+ my $objecttype = "vir" . $object . "DefPtr";
+ $apiname .= $action . "ACL";
+
+ if ($arg eq "interface") {
+ $arg = "iface";
+ }
+
+ my @argdecls;
+ push @argdecls, "virConnectPtr conn";
+ if ($object ne "Connect") {
+ if ($object eq "StorageVol") {
+ push @argdecls, "virStoragePoolDefPtr pool";
+ }
+ push @argdecls, "$objecttype $arg";
+ }
+ if ($checkflags) {
+ push @argdecls, "unsigned int flags";
+ }
+
+ if ($mode eq "aclheader") {
+ print "extern int $apiname(" . join(", ", @argdecls) . ");\n";
+ } else {
+ my @argvars;
+ push @argvars, "mgr";
+ push @argvars, "conn->driver->name";
+ if ($object ne "Connect") {
+ if ($object eq "StorageVol") {
+ push @argvars, "pool";
+ }
+ push @argvars, $arg;
+ }
+
+ if ($action eq "Check") {
+ print "/* Returns: -1 on error, 0 on denied, 1 on allowed */\n";
+ } else {
+ print "/* Returns: -1 on error (denied==error), 0 on allowed */\n";
+ }
+ print "int $apiname(" . join(", ", @argdecls) . ")\n";
+ print "{\n";
+ print " virAccessManagerPtr mgr;\n";
+ print " int rv;\n";
+ print "\n";
+ print " if (!(mgr = virAccessManagerGetDefault()))\n";
+ print " return -1;\n";
+ print "\n";
+
+ foreach my $acl (@acl) {
+ my $perm = "vir_access_perm_" . $acl->{object} . "_" . $acl->{perm};
+ $perm =~ tr/a-z/A-Z/;
+
+ my $method = "virAccessManagerCheck" . $object;
+ my $space = ' ' x length($method);
+ print " if (";
+ if (defined $acl->{flags}) {
+ my $flags = $acl->{flags};
+ if ($flags =~ /^\!/) {
+ $flags = substr $flags, 1;
+ print "((flags & ($flags)) == 0) &&\n";
+ } else {
+ print "((flags & ($flags)) == ($flags)) &&\n";
+ }
+ print " ";
+ }
+ print "(rv = $method(" . join(", ", @argvars, $perm) . ")) <= 0) {\n";
+ print " virObjectUnref(mgr);\n";
+ if ($action eq "Ensure") {
+ print " if (rv == 0)\n";
+ print " virReportError(VIR_ERR_ACCESS_DENIED, NULL);\n";
+ print " return -1;\n";
+ } else {
+ print " return rv;\n";
+ }
+ print " }";
+ print "\n";
+ }
+
+ print " virObjectUnref(mgr);\n";
+ if ($action eq "Check") {
+ print " return 1;\n";
+ } else {
+ print " return 0;\n";
+ }
+ print "}\n\n";
+ }
+ }
+ }
}