diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 08fa15d53..e0386f021 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -144,6 +144,11 @@
 			"ImportPath": "github.com/d2g/dhcp4server/leasepool/memorypool",
 			"Rev": "477b11cea4dcc56af002849238d4f9c1e093c744"
 		},
+		{
+			"ImportPath": "github.com/godbus/dbus",
+			"Comment": "v4.1.0-6-g885f9cc",
+			"Rev": "885f9cc04c9c1a6a61a2008e211d36c5737be3f5"
+		},
 		{
 			"ImportPath": "github.com/j-keck/arping",
 			"Rev": "2cf9dc699c5640a7e2c81403a44127bf28033600"
diff --git a/README.md b/README.md
index f156bbbae..ca904a51d 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ Read [CONTRIBUTING](CONTRIBUTING.md) for build and test instructions.
 * `portmap`: An iptables-based portmapping plugin. Maps ports from the host's address space to the container.
 * `bandwidth`: Allows bandwidth-limiting through use of traffic control tbf (ingress/egress).
 * `sbr`: A plugin that configures source based routing for an interface (from which it is chained).
+* `firewall`: A firewall plugin which uses iptables or firewalld to add rules to allow traffic to/from the container.
 
 ### Sample
 The sample plugin provides an example for building your own plugin.
diff --git a/plugins/linux_only.txt b/plugins/linux_only.txt
new file mode 100644
index 000000000..b789fb4c3
--- /dev/null
+++ b/plugins/linux_only.txt
@@ -0,0 +1,12 @@
+plugins/ipam/dhcp
+plugins/main/bridge
+plugins/main/host-device
+plugins/main/ipvlan
+plugins/main/loopback
+plugins/main/macvlan
+plugins/main/ptp
+plugins/main/vlan
+plugins/meta/portmap
+plugins/meta/tuning
+plugins/meta/bandwidth
+plugins/meta/firewall
diff --git a/plugins/meta/firewall/README.md b/plugins/meta/firewall/README.md
new file mode 100644
index 000000000..f73a41213
--- /dev/null
+++ b/plugins/meta/firewall/README.md
@@ -0,0 +1,135 @@
+# firewall plugin
+
+## Overview
+
+This plugin creates firewall rules to allow traffic to/from container IP address via the host network .
+It does not create any network interfaces and therefore does not set up connectivity by itself.
+It is intended to be used as a chained plugins.
+
+## Operation
+The following network configuration file
+
+```json
+{
+    "cniVersion": "0.3.1",
+    "name": "bridge-firewalld",
+    "plugins": [
+      {
+        "type": "bridge",
+        "bridge": "cni0",
+        "isGateway": true,
+        "ipMasq": true,
+        "ipam": {
+            "type": "host-local",
+            "subnet": "10.88.0.0/16",
+            "routes": [
+                { "dst": "0.0.0.0/0" }
+            ]
+        }
+      },
+      {
+        "type": "firewall",
+      }
+    ]
+}
+```
+
+will allow any IP addresses configured by earlier plugins to send/receive traffic via the host.
+
+A successful result would simply be an empty result, unless a previous plugin passed a previous result, in which case this plugin will return that previous result.
+
+## Backends
+
+This plugin supports multiple firewall backends that implement the desired functionality.
+Available backends include `iptables` and `firewalld` and may be selected with the `backend` key.
+If no `backend` key is given, the plugin will use firewalld if the service exists on the D-Bus system bus.
+If no firewalld service is found, it will fall back to iptables.
+
+## firewalld backend rule structure
+When the `firewalld` backend is used, this example will place the IPAM allocated address for the container (e.g. 10.88.0.2) into firewalld's `trusted` zone, allowing it to send/receive traffic.
+
+
+A sample standalone config list (with the file extension .conflist) using firewalld backend might
+look like:
+
+```json
+{
+    "cniVersion": "0.3.1",
+    "name": "bridge-firewalld",
+    "plugins": [
+      {
+        "type": "bridge",
+        "bridge": "cni0",
+        "isGateway": true,
+        "ipMasq": true,
+        "ipam": {
+            "type": "host-local",
+            "subnet": "10.88.0.0/16",
+            "routes": [
+                { "dst": "0.0.0.0/0" }
+            ]
+        }
+      },
+      {
+        "type": "firewall",
+	"backend": "firewalld"
+      }
+    ]
+}
+```
+
+
+`FORWARD_IN_ZONES_SOURCE` chain:
+- `-d 10.88.0.2 -j FWDI_trusted`
+
+`CNI_FORWARD_OUT_ZONES_SOURCE` chain:
+- `-s 10.88.0.2 -j FWDO_trusted`
+
+
+## iptables backend rule structure
+
+A sample standalone config list (with the file extension .conflist) using iptables backend might
+look like:
+
+```json
+{
+    "cniVersion": "0.3.1",
+    "name": "bridge-firewalld",
+    "plugins": [
+      {
+        "type": "bridge",
+        "bridge": "cni0",
+        "isGateway": true,
+        "ipMasq": true,
+        "ipam": {
+            "type": "host-local",
+            "subnet": "10.88.0.0/16",
+            "routes": [
+                { "dst": "0.0.0.0/0" }
+            ]
+        }
+      },
+      {
+        "type": "firewall",
+	"backend": "iptables"
+      }
+    ]
+}
+```
+
+When the `iptables` backend is used, the above example will create two new iptables chains in the `filter` table and add rules that allow the given interface to send/receive traffic.
+
+### FORWARD
+A new chain, CNI-FORWARD is added to the FORWARD chain.  CNI-FORWARD is the chain where rules will be added
+when containers are created and from where rules will be removed when containers terminate.
+
+`FORWARD` chain:
+- `-j CNI-FORWARD`
+
+CNI-FORWARD will have a pair of rules added, one for each direction, using the IPAM assigned IP address
+of the container as shown:
+
+`CNI_FORWARD` chain:
+- `-s 10.88.0.2 -m conntrack --ctstate RELATED,ESTABLISHED -j CNI-FORWARD`
+- `-d 10.88.0.2 -j CNI-FORWARD`
+
diff --git a/plugins/meta/firewall/firewall.go b/plugins/meta/firewall/firewall.go
new file mode 100644
index 000000000..ccb0545bc
--- /dev/null
+++ b/plugins/meta/firewall/firewall.go
@@ -0,0 +1,182 @@
+// Copyright 2016 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This is a "meta-plugin". It reads in its own netconf, it does not create
+// any network interface but just changes the network sysctl.
+
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+
+	"github.com/containernetworking/cni/pkg/skel"
+	"github.com/containernetworking/cni/pkg/types"
+	"github.com/containernetworking/cni/pkg/types/current"
+	"github.com/containernetworking/cni/pkg/version"
+	"github.com/containernetworking/plugins/pkg/ns"
+)
+
+// FirewallNetConf represents the firewall configuration.
+type FirewallNetConf struct {
+	types.NetConf
+
+	// Backend is the firewall type to add rules to.  Allowed values are
+	// 'iptables' and 'firewalld'.
+	Backend string `json:"backend"`
+
+	// IptablesAdminChainName is an optional name to use instead of the default
+	// admin rules override chain name that includes the interface name.
+	IptablesAdminChainName string `json:"iptablesAdminChainName,omitempty"`
+
+	// FirewalldZone is an optional firewalld zone to place the interface into.  If
+	// the firewalld backend is used but the zone is not given, it defaults
+	// to 'trusted'
+	FirewalldZone string `json:"firewalldZone,omitempty"`
+}
+
+type FirewallBackend interface {
+	Add(*FirewallNetConf, *current.Result) error
+	Del(*FirewallNetConf, *current.Result) error
+	Check(*FirewallNetConf, *current.Result) error
+}
+
+func ipString(ip net.IPNet) string {
+	if ip.IP.To4() == nil {
+		return ip.IP.String() + "/128"
+	}
+	return ip.IP.String() + "/32"
+}
+
+func parseConf(data []byte) (*FirewallNetConf, *current.Result, error) {
+	conf := FirewallNetConf{}
+	if err := json.Unmarshal(data, &conf); err != nil {
+		return nil, nil, fmt.Errorf("failed to load netconf: %v", err)
+	}
+
+	// Parse previous result.
+	if conf.RawPrevResult == nil {
+		return nil, nil, fmt.Errorf("missing prevResult from earlier plugin")
+	}
+
+	// Parse previous result.
+	var result *current.Result
+	var err error
+	if err = version.ParsePrevResult(&conf.NetConf); err != nil {
+		return nil, nil, fmt.Errorf("could not parse prevResult: %v", err)
+	}
+
+	result, err = current.NewResultFromResult(conf.PrevResult)
+	if err != nil {
+		return nil, nil, fmt.Errorf("could not convert result to current version: %v", err)
+	}
+
+	// Default the firewalld zone to trusted
+	if conf.FirewalldZone == "" {
+		conf.FirewalldZone = "trusted"
+	}
+
+	return &conf, result, nil
+}
+
+func getBackend(conf *FirewallNetConf) (FirewallBackend, error) {
+	switch conf.Backend {
+	case "iptables":
+		return newIptablesBackend(conf)
+	case "firewalld":
+		return newFirewalldBackend(conf)
+	}
+
+	// Default to firewalld if it's running
+	if isFirewalldRunning() {
+		return newFirewalldBackend(conf)
+	}
+
+	// Otherwise iptables
+	return newIptablesBackend(conf)
+}
+
+func cmdAdd(args *skel.CmdArgs) error {
+	conf, result, err := parseConf(args.StdinData)
+	if err != nil {
+		return err
+	}
+
+	backend, err := getBackend(conf)
+	if err != nil {
+		return err
+	}
+
+	if err := backend.Add(conf, result); err != nil {
+		return err
+	}
+
+	if result == nil {
+		result = &current.Result{}
+	}
+	return types.PrintResult(result, conf.CNIVersion)
+}
+
+func cmdDel(args *skel.CmdArgs) error {
+	conf, result, err := parseConf(args.StdinData)
+	if err != nil {
+		return err
+	}
+
+	backend, err := getBackend(conf)
+	if err != nil {
+		return err
+	}
+
+	// Tolerate errors if the container namespace has been torn down already
+	containerNS, err := ns.GetNS(args.Netns)
+	if err == nil {
+		defer containerNS.Close()
+	}
+
+	// Runtime errors are ignored
+	if err := backend.Del(conf, result); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func main() {
+	skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.PluginSupports("0.4.0"), "TODO")
+}
+
+func cmdCheck(args *skel.CmdArgs) error {
+	conf, result, err := parseConf(args.StdinData)
+	if err != nil {
+		return err
+	}
+
+	// Ensure we have previous result.
+	if result == nil {
+		return fmt.Errorf("Required prevResult missing")
+	}
+
+	backend, err := getBackend(conf)
+	if err != nil {
+		return err
+	}
+
+	if err := backend.Check(conf, result); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/plugins/meta/firewall/firewall_firewalld_test.go b/plugins/meta/firewall/firewall_firewalld_test.go
new file mode 100644
index 000000000..68a00793e
--- /dev/null
+++ b/plugins/meta/firewall/firewall_firewalld_test.go
@@ -0,0 +1,343 @@
+// Copyright 2018 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"os/exec"
+	"strings"
+	"sync"
+	"syscall"
+
+	"github.com/containernetworking/cni/pkg/invoke"
+	"github.com/containernetworking/cni/pkg/skel"
+	"github.com/containernetworking/cni/pkg/types/current"
+	"github.com/containernetworking/plugins/pkg/ns"
+	"github.com/containernetworking/plugins/pkg/testutils"
+
+	"github.com/godbus/dbus"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+const (
+	confTmpl = `{
+  "cniVersion": "0.3.1",
+  "name": "firewalld-test",
+  "type": "firewall",
+  "backend": "firewalld",
+  "zone": "trusted",
+  "prevResult": {
+    "cniVersion": "0.3.0",
+    "interfaces": [
+      {"name": "%s", "sandbox": "%s"}
+    ],
+    "ips": [
+      {
+        "version": "4",
+        "address": "10.0.0.2/24",
+        "gateway": "10.0.0.1",
+        "interface": 0
+      }
+    ]
+  }
+}`
+	ifname = "eth0"
+)
+
+type fakeFirewalld struct {
+	zone   string
+	source string
+}
+
+func (f *fakeFirewalld) clear() {
+	f.zone = ""
+	f.source = ""
+}
+
+func (f *fakeFirewalld) AddSource(zone, source string) (string, *dbus.Error) {
+	f.zone = zone
+	f.source = source
+	return "", nil
+}
+
+func (f *fakeFirewalld) RemoveSource(zone, source string) (string, *dbus.Error) {
+	f.zone = zone
+	f.source = source
+	return "", nil
+}
+
+func (f *fakeFirewalld) QuerySource(zone, source string) (bool, *dbus.Error) {
+	if f.zone != zone {
+		return false, nil
+	}
+	if f.source != source {
+		return false, nil
+	}
+	return true, nil
+}
+
+func spawnSessionDbus(wg *sync.WaitGroup) (string, *exec.Cmd) {
+	// Start a private D-Bus session bus
+	path, err := invoke.FindInPath("dbus-daemon", []string{
+		"/bin", "/sbin", "/usr/bin", "/usr/sbin",
+	})
+	Expect(err).NotTo(HaveOccurred())
+	cmd := exec.Command(path, "--session", "--print-address", "--nofork", "--nopidfile")
+	stdout, err := cmd.StdoutPipe()
+	Expect(err).NotTo(HaveOccurred())
+	err = cmd.Start()
+	Expect(err).NotTo(HaveOccurred())
+
+	// Wait for dbus-daemon to print the bus address
+	bytes, err := bufio.NewReader(stdout).ReadString('\n')
+	Expect(err).NotTo(HaveOccurred())
+	busAddr := strings.TrimSpace(string(bytes))
+	Expect(strings.HasPrefix(busAddr, "unix:abstract")).To(BeTrue())
+
+	var startWg sync.WaitGroup
+	wg.Add(1)
+	startWg.Add(1)
+	go func() {
+		defer GinkgoRecover()
+
+		startWg.Done()
+		err = cmd.Wait()
+		Expect(err).NotTo(HaveOccurred())
+		wg.Done()
+	}()
+
+	startWg.Wait()
+	return busAddr, cmd
+}
+
+var _ = Describe("firewalld test", func() {
+	var (
+		targetNs ns.NetNS
+		cmd      *exec.Cmd
+		conn     *dbus.Conn
+		wg       sync.WaitGroup
+		fwd      *fakeFirewalld
+		busAddr  string
+	)
+
+	BeforeEach(func() {
+		var err error
+		targetNs, err = testutils.NewNS()
+		Expect(err).NotTo(HaveOccurred())
+
+		// Start a private D-Bus session bus
+		busAddr, cmd = spawnSessionDbus(&wg)
+		conn, err = dbus.Dial(busAddr)
+		Expect(err).NotTo(HaveOccurred())
+		err = conn.Auth(nil)
+		Expect(err).NotTo(HaveOccurred())
+		err = conn.Hello()
+		Expect(err).NotTo(HaveOccurred())
+
+		// Start our fake firewalld
+		reply, err := conn.RequestName(firewalldName, dbus.NameFlagDoNotQueue)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(reply).To(Equal(dbus.RequestNameReplyPrimaryOwner))
+
+		fwd = &fakeFirewalld{}
+		// Because firewalld D-Bus methods start with lower-case, and
+		// because in Go lower-case methods are private, we need to remap
+		// Go public methods to the D-Bus name
+		methods := map[string]string{
+			"AddSource":    firewalldAddSourceMethod,
+			"QuerySource":  firewalldQuerySourceMethod,
+			"RemoveSource": firewalldRemoveSourceMethod,
+		}
+		conn.ExportWithMap(fwd, methods, firewalldPath, firewalldZoneInterface)
+
+		// Make sure the plugin uses our private session bus
+		testConn = conn
+	})
+
+	AfterEach(func() {
+		_, err := conn.ReleaseName(firewalldName)
+		Expect(err).NotTo(HaveOccurred())
+
+		err = cmd.Process.Signal(syscall.SIGTERM)
+		Expect(err).NotTo(HaveOccurred())
+
+		wg.Wait()
+	})
+
+	It("works with a 0.3.1 config", func() {
+		Expect(isFirewalldRunning()).To(BeTrue())
+
+		conf := fmt.Sprintf(confTmpl, ifname, targetNs.Path())
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNs.Path(),
+			IfName:      ifname,
+			StdinData:   []byte(conf),
+		}
+		_, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
+			return cmdAdd(args)
+		})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(fwd.zone).To(Equal("trusted"))
+		Expect(fwd.source).To(Equal("10.0.0.2/32"))
+		fwd.clear()
+
+		err = testutils.CmdDel(targetNs.Path(), args.ContainerID, ifname, func() error {
+			return cmdDel(args)
+		})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(fwd.zone).To(Equal("trusted"))
+		Expect(fwd.source).To(Equal("10.0.0.2/32"))
+	})
+
+	It("defaults to the firewalld backend", func() {
+		conf := `{
+		  "cniVersion": "0.3.1",
+		  "name": "firewalld-test",
+		  "type": "firewall",
+		  "zone": "trusted",
+		  "prevResult": {
+		    "cniVersion": "0.3.0",
+		    "interfaces": [
+		      {"name": "eth0", "sandbox": "/foobar"}
+		    ],
+		    "ips": [
+		      {
+			"version": "4",
+			"address": "10.0.0.2/24",
+			"gateway": "10.0.0.1",
+			"interface": 0
+		      }
+		    ]
+		  }
+		}`
+
+		Expect(isFirewalldRunning()).To(BeTrue())
+
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNs.Path(),
+			IfName:      ifname,
+			StdinData:   []byte(conf),
+		}
+		_, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
+			return cmdAdd(args)
+		})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(fwd.zone).To(Equal("trusted"))
+		Expect(fwd.source).To(Equal("10.0.0.2/32"))
+	})
+
+	It("passes through the prevResult", func() {
+		conf := `{
+		  "cniVersion": "0.3.1",
+		  "name": "firewalld-test",
+		  "type": "firewall",
+		  "zone": "trusted",
+		  "prevResult": {
+		    "cniVersion": "0.3.0",
+		    "interfaces": [
+		      {"name": "eth0", "sandbox": "/foobar"}
+		    ],
+		    "ips": [
+		      {
+			"version": "4",
+			"address": "10.0.0.2/24",
+			"gateway": "10.0.0.1",
+			"interface": 0
+		      }
+		    ]
+		  }
+		}`
+
+		Expect(isFirewalldRunning()).To(BeTrue())
+
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNs.Path(),
+			IfName:      ifname,
+			StdinData:   []byte(conf),
+		}
+		r, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
+			return cmdAdd(args)
+		})
+		Expect(err).NotTo(HaveOccurred())
+
+		result, err := current.GetResult(r)
+		Expect(err).NotTo(HaveOccurred())
+
+		Expect(len(result.Interfaces)).To(Equal(1))
+		Expect(result.Interfaces[0].Name).To(Equal("eth0"))
+		Expect(len(result.IPs)).To(Equal(1))
+		Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
+	})
+
+	It("works with a 0.4.0 config, including Check", func() {
+		Expect(isFirewalldRunning()).To(BeTrue())
+
+		conf := `{
+			  "cniVersion": "0.4.0",
+			  "name": "firewalld-test",
+			  "type": "firewall",
+			  "backend": "firewalld",
+			  "zone": "trusted",
+			  "prevResult": {
+			    "cniVersion": "0.4.0",
+			    "interfaces": [
+			      {"name": "eth0", "sandbox": "/foobar"}
+			    ],
+			    "ips": [
+			      {
+				"version": "4",
+				"address": "10.0.0.2/24",
+				"gateway": "10.0.0.1",
+				"interface": 0
+			      }
+			    ]
+			  }
+			}`
+
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNs.Path(),
+			IfName:      ifname,
+			StdinData:   []byte(conf),
+		}
+		r, _, err := testutils.CmdAddWithArgs(args, func() error {
+			return cmdAdd(args)
+		})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(fwd.zone).To(Equal("trusted"))
+		Expect(fwd.source).To(Equal("10.0.0.2/32"))
+
+		_, err = current.GetResult(r)
+		Expect(err).NotTo(HaveOccurred())
+
+		err = testutils.CmdCheckWithArgs(args, func() error {
+			return cmdCheck(args)
+		})
+		Expect(err).NotTo(HaveOccurred())
+
+		err = testutils.CmdDelWithArgs(args, func() error {
+			return cmdDel(args)
+		})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(fwd.zone).To(Equal("trusted"))
+		Expect(fwd.source).To(Equal("10.0.0.2/32"))
+	})
+})
diff --git a/plugins/meta/firewall/firewall_iptables_test.go b/plugins/meta/firewall/firewall_iptables_test.go
new file mode 100644
index 000000000..6c7358f42
--- /dev/null
+++ b/plugins/meta/firewall/firewall_iptables_test.go
@@ -0,0 +1,512 @@
+// Copyright 2017 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+
+	"github.com/containernetworking/cni/pkg/skel"
+	"github.com/containernetworking/cni/pkg/types"
+	"github.com/containernetworking/cni/pkg/types/current"
+	"github.com/containernetworking/cni/pkg/version"
+	"github.com/containernetworking/plugins/pkg/ns"
+	"github.com/containernetworking/plugins/pkg/testutils"
+
+	"github.com/vishvananda/netlink"
+
+	"github.com/coreos/go-iptables/iptables"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+func findChains(chains []string) (bool, bool) {
+	var foundAdmin, foundPriv bool
+	for _, ch := range chains {
+		if ch == "CNI-ADMIN" {
+			foundAdmin = true
+		} else if ch == "CNI-FORWARD" {
+			foundPriv = true
+		}
+	}
+	return foundAdmin, foundPriv
+}
+
+func findForwardJumpRules(rules []string) (bool, bool) {
+	var foundAdmin, foundPriv bool
+	for _, rule := range rules {
+		if strings.Contains(rule, "-j CNI-ADMIN") {
+			foundAdmin = true
+		} else if strings.Contains(rule, "-j CNI-FORWARD") {
+			foundPriv = true
+		}
+	}
+	return foundAdmin, foundPriv
+}
+
+func findForwardAllowRules(rules []string, ip string) (bool, bool) {
+	var foundOne, foundTwo bool
+	for _, rule := range rules {
+		if !strings.HasSuffix(rule, "-j ACCEPT") {
+			continue
+		}
+		if strings.Contains(rule, fmt.Sprintf(" -s %s ", ip)) {
+			foundOne = true
+		} else if strings.Contains(rule, fmt.Sprintf(" -d %s ", ip)) && strings.Contains(rule, "RELATED,ESTABLISHED") {
+			foundTwo = true
+		}
+	}
+	return foundOne, foundTwo
+}
+
+func getPrevResult(bytes []byte) *current.Result {
+	type TmpConf struct {
+		types.NetConf
+		RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
+		PrevResult    *current.Result        `json:"-"`
+	}
+
+	conf := &TmpConf{}
+	err := json.Unmarshal(bytes, conf)
+	Expect(err).NotTo(HaveOccurred())
+	if conf.RawPrevResult == nil {
+		return nil
+	}
+
+	resultBytes, err := json.Marshal(conf.RawPrevResult)
+	Expect(err).NotTo(HaveOccurred())
+	res, err := version.NewResult(conf.CNIVersion, resultBytes)
+	Expect(err).NotTo(HaveOccurred())
+	prevResult, err := current.NewResultFromResult(res)
+	Expect(err).NotTo(HaveOccurred())
+
+	return prevResult
+}
+
+func validateFullRuleset(bytes []byte) {
+	prevResult := getPrevResult(bytes)
+
+	for _, ip := range prevResult.IPs {
+		ipt, err := iptables.NewWithProtocol(protoForIP(ip.Address))
+		Expect(err).NotTo(HaveOccurred())
+
+		// Ensure chains
+		chains, err := ipt.ListChains("filter")
+		Expect(err).NotTo(HaveOccurred())
+		foundAdmin, foundPriv := findChains(chains)
+		Expect(foundAdmin).To(Equal(true))
+		Expect(foundPriv).To(Equal(true))
+
+		// Look for the FORWARD chain jump rules to our custom chains
+		rules, err := ipt.List("filter", "FORWARD")
+		Expect(err).NotTo(HaveOccurred())
+		Expect(len(rules)).Should(BeNumerically(">", 1))
+		_, foundPriv = findForwardJumpRules(rules)
+		Expect(foundPriv).To(Equal(true))
+
+		// Look for the allow rules in our custom FORWARD chain
+		rules, err = ipt.List("filter", "CNI-FORWARD")
+		Expect(err).NotTo(HaveOccurred())
+		Expect(len(rules)).Should(BeNumerically(">", 1))
+		foundAdmin, _ = findForwardJumpRules(rules)
+		Expect(foundAdmin).To(Equal(true))
+
+		// Look for the IP allow rules
+		foundOne, foundTwo := findForwardAllowRules(rules, ipString(ip.Address))
+		Expect(foundOne).To(Equal(true))
+		Expect(foundTwo).To(Equal(true))
+	}
+}
+
+func validateCleanedUp(bytes []byte) {
+	prevResult := getPrevResult(bytes)
+
+	for _, ip := range prevResult.IPs {
+		ipt, err := iptables.NewWithProtocol(protoForIP(ip.Address))
+		Expect(err).NotTo(HaveOccurred())
+
+		// Our private and admin chains don't get cleaned up
+		chains, err := ipt.ListChains("filter")
+		Expect(err).NotTo(HaveOccurred())
+		foundAdmin, foundPriv := findChains(chains)
+		Expect(foundAdmin).To(Equal(true))
+		Expect(foundPriv).To(Equal(true))
+
+		// Look for the FORWARD chain jump rules to our custom chains
+		rules, err := ipt.List("filter", "FORWARD")
+		Expect(err).NotTo(HaveOccurred())
+		_, foundPriv = findForwardJumpRules(rules)
+		Expect(foundPriv).To(Equal(true))
+
+		// Look for the allow rules in our custom FORWARD chain
+		rules, err = ipt.List("filter", "CNI-FORWARD")
+		Expect(err).NotTo(HaveOccurred())
+		foundAdmin, _ = findForwardJumpRules(rules)
+		Expect(foundAdmin).To(Equal(true))
+
+		// Expect no IP address rules for this IP
+		foundOne, foundTwo := findForwardAllowRules(rules, ipString(ip.Address))
+		Expect(foundOne).To(Equal(false))
+		Expect(foundTwo).To(Equal(false))
+	}
+}
+
+var _ = Describe("firewall plugin iptables backend", func() {
+	var originalNS, targetNS ns.NetNS
+	const IFNAME string = "dummy0"
+
+	fullConf := []byte(`{
+		"name": "test",
+		"type": "firewall",
+		"backend": "iptables",
+		"ifName": "dummy0",
+		"cniVersion": "0.3.1",
+		"prevResult": {
+			"interfaces": [
+				{"name": "dummy0"}
+			],
+			"ips": [
+				{
+					"version": "4",
+					"address": "10.0.0.2/24",
+					"interface": 0
+				},
+				{
+					"version": "6",
+					"address": "2001:db8:1:2::1/64",
+					"interface": 0
+				}
+			]
+		}
+	}`)
+
+	BeforeEach(func() {
+		// Create a new NetNS so we don't modify the host
+		var err error
+		originalNS, err = testutils.NewNS()
+		Expect(err).NotTo(HaveOccurred())
+
+		err = originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			err = netlink.LinkAdd(&netlink.Dummy{
+				LinkAttrs: netlink.LinkAttrs{
+					Name: IFNAME,
+				},
+			})
+			Expect(err).NotTo(HaveOccurred())
+			_, err = netlink.LinkByName(IFNAME)
+			Expect(err).NotTo(HaveOccurred())
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+
+		targetNS, err = testutils.NewNS()
+		Expect(err).NotTo(HaveOccurred())
+	})
+
+	AfterEach(func() {
+		Expect(originalNS.Close()).To(Succeed())
+		Expect(targetNS.Close()).To(Succeed())
+	})
+
+	It("passes prevResult through unchanged", func() {
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNS.Path(),
+			IfName:      IFNAME,
+			StdinData:   fullConf,
+		}
+
+		err := originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			r, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
+				return cmdAdd(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+
+			result, err := current.GetResult(r)
+			Expect(err).NotTo(HaveOccurred())
+
+			Expect(len(result.Interfaces)).To(Equal(1))
+			Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
+			Expect(len(result.IPs)).To(Equal(2))
+			Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
+			Expect(result.IPs[1].Address.String()).To(Equal("2001:db8:1:2::1/64"))
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+	})
+
+	It("installs the right iptables rules on the host", func() {
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNS.Path(),
+			IfName:      IFNAME,
+			StdinData:   fullConf,
+		}
+
+		err := originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
+				return cmdAdd(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+
+			validateFullRuleset(fullConf)
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+	})
+
+	It("correctly handles a custom IptablesAdminChainName", func() {
+		conf := []byte(`{
+	"name": "test",
+	"type": "firewall",
+	"backend": "iptables",
+	"ifName": "dummy0",
+	"cniVersion": "0.3.1",
+	"iptablesAdminChainName": "CNI-foobar",
+	"prevResult": {
+		"interfaces": [
+			{"name": "dummy0"}
+		],
+		"ips": [
+			{
+				"version": "4",
+				"address": "10.0.0.2/24",
+				"interface": 0
+			},
+			{
+				"version": "6",
+				"address": "2001:db8:1:2::1/64",
+				"interface": 0
+			}
+		]
+	}
+}`)
+
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNS.Path(),
+			IfName:      IFNAME,
+			StdinData:   conf,
+		}
+
+		err := originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, conf, func() error {
+				return cmdAdd(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+
+			var ipt *iptables.IPTables
+			for _, proto := range []iptables.Protocol{iptables.ProtocolIPv4, iptables.ProtocolIPv6} {
+				ipt, err = iptables.NewWithProtocol(proto)
+				Expect(err).NotTo(HaveOccurred())
+
+				// Ensure custom admin chain name
+				chains, err := ipt.ListChains("filter")
+				Expect(err).NotTo(HaveOccurred())
+				var foundAdmin bool
+				for _, ch := range chains {
+					if ch == "CNI-foobar" {
+						foundAdmin = true
+					}
+				}
+				Expect(foundAdmin).To(Equal(true))
+			}
+
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+	})
+
+	It("cleans up on delete", func() {
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNS.Path(),
+			IfName:      IFNAME,
+			StdinData:   fullConf,
+		}
+
+		err := originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
+				return cmdAdd(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+			validateFullRuleset(fullConf)
+
+			err = testutils.CmdDel(targetNS.Path(), args.ContainerID, IFNAME, func() error {
+				return cmdDel(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+			validateCleanedUp(fullConf)
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+	})
+
+	It("installs the right iptables rules on the host v4.0.x and check is successful", func() {
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNS.Path(),
+			IfName:      IFNAME,
+			StdinData:   fullConf,
+		}
+
+		err := originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
+				return cmdAdd(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+
+			validateFullRuleset(fullConf)
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+	})
+
+	It("cleans up on delete v4.0.x", func() {
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNS.Path(),
+			IfName:      IFNAME,
+			StdinData:   fullConf,
+		}
+
+		err := originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
+				return cmdAdd(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+			validateFullRuleset(fullConf)
+
+			err = testutils.CmdDel(targetNS.Path(), args.ContainerID, IFNAME, func() error {
+				return cmdDel(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+			validateCleanedUp(fullConf)
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+	})
+})
+
+var _ = Describe("firewall plugin iptables backend v0.4.x", func() {
+	var originalNS, targetNS ns.NetNS
+	const IFNAME string = "dummy0"
+
+	fullConf := []byte(`{
+		"name": "test",
+		"type": "firewall",
+		"backend": "iptables",
+		"ifName": "dummy0",
+		"cniVersion": "0.4.0",
+		"prevResult": {
+			"interfaces": [
+				{"name": "dummy0"}
+			],
+			"ips": [
+				{
+					"version": "4",
+					"address": "10.0.0.2/24",
+					"interface": 0
+				},
+				{
+					"version": "6",
+					"address": "2001:db8:1:2::1/64",
+					"interface": 0
+				}
+			]
+		}
+	}`)
+
+	BeforeEach(func() {
+		// Create a new NetNS so we don't modify the host
+		var err error
+		originalNS, err = testutils.NewNS()
+		Expect(err).NotTo(HaveOccurred())
+
+		err = originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			err = netlink.LinkAdd(&netlink.Dummy{
+				LinkAttrs: netlink.LinkAttrs{
+					Name: IFNAME,
+				},
+			})
+			Expect(err).NotTo(HaveOccurred())
+			_, err = netlink.LinkByName(IFNAME)
+			Expect(err).NotTo(HaveOccurred())
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+
+		targetNS, err = testutils.NewNS()
+		Expect(err).NotTo(HaveOccurred())
+	})
+
+	AfterEach(func() {
+		Expect(originalNS.Close()).To(Succeed())
+		Expect(targetNS.Close()).To(Succeed())
+	})
+
+	It("installs iptables rules, Check rules then cleans up on delete using v4.0.x", func() {
+		args := &skel.CmdArgs{
+			ContainerID: "dummy",
+			Netns:       targetNS.Path(),
+			IfName:      IFNAME,
+			StdinData:   fullConf,
+		}
+
+		err := originalNS.Do(func(ns.NetNS) error {
+			defer GinkgoRecover()
+
+			r, _, err := testutils.CmdAddWithArgs(args, func() error {
+				return cmdAdd(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+
+			_, err = current.GetResult(r)
+			Expect(err).NotTo(HaveOccurred())
+
+			err = testutils.CmdCheckWithArgs(args, func() error {
+				return cmdCheck(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+			validateFullRuleset(fullConf)
+
+			err = testutils.CmdDelWithArgs(args, func() error {
+				return cmdDel(args)
+			})
+			Expect(err).NotTo(HaveOccurred())
+			validateCleanedUp(fullConf)
+			return nil
+		})
+		Expect(err).NotTo(HaveOccurred())
+	})
+})
diff --git a/plugins/meta/firewall/firewall_suite_test.go b/plugins/meta/firewall/firewall_suite_test.go
new file mode 100644
index 000000000..d3b10e218
--- /dev/null
+++ b/plugins/meta/firewall/firewall_suite_test.go
@@ -0,0 +1,27 @@
+// Copyright 2017 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
+	"testing"
+)
+
+func TestFirewall(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "firewall Suite")
+}
diff --git a/plugins/meta/firewall/firewalld.go b/plugins/meta/firewall/firewalld.go
new file mode 100644
index 000000000..ac9328c3f
--- /dev/null
+++ b/plugins/meta/firewall/firewalld.go
@@ -0,0 +1,122 @@
+// Copyright 2018 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/containernetworking/cni/pkg/types/current"
+	"github.com/godbus/dbus"
+)
+
+const (
+	dbusName               = "org.freedesktop.DBus"
+	dbusPath               = "/org/freedesktop/DBus"
+	dbusGetNameOwnerMethod = "GetNameOwner"
+
+	firewalldName               = "org.fedoraproject.FirewallD1"
+	firewalldPath               = "/org/fedoraproject/FirewallD1"
+	firewalldZoneInterface      = "org.fedoraproject.FirewallD1.zone"
+	firewalldAddSourceMethod    = "addSource"
+	firewalldRemoveSourceMethod = "removeSource"
+	firewalldQuerySourceMethod  = "querySource"
+
+	errZoneAlreadySet = "ZONE_ALREADY_SET"
+)
+
+// Only used for testcases to override the D-Bus connection
+var testConn *dbus.Conn
+
+type fwdBackend struct {
+	conn *dbus.Conn
+}
+
+// fwdBackend implements the FirewallBackend interface
+var _ FirewallBackend = &fwdBackend{}
+
+func getConn() (*dbus.Conn, error) {
+	if testConn != nil {
+		return testConn, nil
+	}
+	return dbus.SystemBus()
+}
+
+// isFirewalldRunning checks whether firewalld is running.
+func isFirewalldRunning() bool {
+	conn, err := getConn()
+	if err != nil {
+		return false
+	}
+
+	dbusObj := conn.Object(dbusName, dbusPath)
+	var res string
+	if err := dbusObj.Call(dbusName+"."+dbusGetNameOwnerMethod, 0, firewalldName).Store(&res); err != nil {
+		return false
+	}
+
+	return true
+}
+
+func newFirewalldBackend(conf *FirewallNetConf) (FirewallBackend, error) {
+	conn, err := getConn()
+	if err != nil {
+		return nil, err
+	}
+
+	backend := &fwdBackend{
+		conn: conn,
+	}
+	return backend, nil
+}
+
+func (fb *fwdBackend) Add(conf *FirewallNetConf, result *current.Result) error {
+	for _, ip := range result.IPs {
+		ipStr := ipString(ip.Address)
+		// Add a firewalld rule which assigns the given source IP to the given zone
+		firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
+		var res string
+		if err := firewalldObj.Call(firewalldZoneInterface+"."+firewalldAddSourceMethod, 0, conf.FirewalldZone, ipStr).Store(&res); err != nil {
+			if !strings.Contains(err.Error(), errZoneAlreadySet) {
+				return fmt.Errorf("failed to add the address %v to %v zone: %v", ipStr, conf.FirewalldZone, err)
+			}
+		}
+	}
+	return nil
+}
+
+func (fb *fwdBackend) Del(conf *FirewallNetConf, result *current.Result) error {
+	for _, ip := range result.IPs {
+		ipStr := ipString(ip.Address)
+		// Remove firewalld rules which assigned the given source IP to the given zone
+		firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
+		var res string
+		firewalldObj.Call(firewalldZoneInterface+"."+firewalldRemoveSourceMethod, 0, conf.FirewalldZone, ipStr).Store(&res)
+	}
+	return nil
+}
+
+func (fb *fwdBackend) Check(conf *FirewallNetConf, result *current.Result) error {
+	for _, ip := range result.IPs {
+		ipStr := ipString(ip.Address)
+		// Check for a firewalld rule for the given source IP to the given zone
+		firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
+		var res bool
+		if err := firewalldObj.Call(firewalldZoneInterface+"."+firewalldQuerySourceMethod, 0, conf.FirewalldZone, ipStr).Store(&res); err != nil {
+			return fmt.Errorf("failed to find the address %v in %v zone", ipStr, conf.FirewalldZone)
+		}
+	}
+	return nil
+}
diff --git a/plugins/meta/firewall/iptables.go b/plugins/meta/firewall/iptables.go
new file mode 100644
index 000000000..faae35c61
--- /dev/null
+++ b/plugins/meta/firewall/iptables.go
@@ -0,0 +1,279 @@
+// Copyright 2016 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This is a "meta-plugin". It reads in its own netconf, it does not create
+// any network interface but just changes the network sysctl.
+
+package main
+
+import (
+	"fmt"
+	"net"
+
+	"github.com/containernetworking/cni/pkg/types/current"
+	"github.com/coreos/go-iptables/iptables"
+)
+
+func getPrivChainRules(ip string) [][]string {
+	var rules [][]string
+	rules = append(rules, []string{"-d", ip, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"})
+	rules = append(rules, []string{"-s", ip, "-j", "ACCEPT"})
+	return rules
+}
+
+func ensureChain(ipt *iptables.IPTables, table, chain string) error {
+	chains, err := ipt.ListChains(table)
+	if err != nil {
+		return fmt.Errorf("failed to list iptables chains: %v", err)
+	}
+	for _, ch := range chains {
+		if ch == chain {
+			return nil
+		}
+	}
+
+	return ipt.NewChain(table, chain)
+}
+
+func generateFilterRule(privChainName string) []string {
+	return []string{"-m", "comment", "--comment", "CNI firewall plugin rules", "-j", privChainName}
+}
+
+func generateAdminRule(adminChainName string) []string {
+	return []string{"-m", "comment", "--comment", "CNI firewall plugin admin overrides", "-j", adminChainName}
+}
+
+func cleanupRules(ipt *iptables.IPTables, privChainName string, rules [][]string) {
+	for _, rule := range rules {
+		ipt.Delete("filter", privChainName, rule...)
+	}
+}
+
+func ensureFirstChainRule(ipt *iptables.IPTables, chain string, rule []string) error {
+	exists, err := ipt.Exists("filter", chain, rule...)
+	if !exists && err == nil {
+		err = ipt.Insert("filter", chain, 1, rule...)
+	}
+	return err
+}
+
+func (ib *iptablesBackend) setupChains(ipt *iptables.IPTables) error {
+	privRule := generateFilterRule(ib.privChainName)
+	adminRule := generateFilterRule(ib.adminChainName)
+
+	// Ensure our private chains exist
+	if err := ensureChain(ipt, "filter", ib.privChainName); err != nil {
+		return err
+	}
+	if err := ensureChain(ipt, "filter", ib.adminChainName); err != nil {
+		return err
+	}
+
+	// Ensure our filter rule exists in the forward chain
+	if err := ensureFirstChainRule(ipt, "FORWARD", privRule); err != nil {
+		return err
+	}
+
+	// Ensure our admin override chain rule exists in our private chain
+	if err := ensureFirstChainRule(ipt, ib.privChainName, adminRule); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func protoForIP(ip net.IPNet) iptables.Protocol {
+	if ip.IP.To4() != nil {
+		return iptables.ProtocolIPv4
+	}
+	return iptables.ProtocolIPv6
+}
+
+func (ib *iptablesBackend) addRules(conf *FirewallNetConf, result *current.Result, ipt *iptables.IPTables, proto iptables.Protocol) error {
+	rules := make([][]string, 0)
+	for _, ip := range result.IPs {
+		if protoForIP(ip.Address) == proto {
+			rules = append(rules, getPrivChainRules(ipString(ip.Address))...)
+		}
+	}
+
+	if len(rules) > 0 {
+		if err := ib.setupChains(ipt); err != nil {
+			return err
+		}
+
+		// Clean up on any errors
+		var err error
+		defer func() {
+			if err != nil {
+				cleanupRules(ipt, ib.privChainName, rules)
+			}
+		}()
+
+		for _, rule := range rules {
+			err = ipt.AppendUnique("filter", ib.privChainName, rule...)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+func (ib *iptablesBackend) delRules(conf *FirewallNetConf, result *current.Result, ipt *iptables.IPTables, proto iptables.Protocol) error {
+	rules := make([][]string, 0)
+	for _, ip := range result.IPs {
+		if protoForIP(ip.Address) == proto {
+			rules = append(rules, getPrivChainRules(ipString(ip.Address))...)
+		}
+	}
+
+	if len(rules) > 0 {
+		cleanupRules(ipt, ib.privChainName, rules)
+	}
+
+	return nil
+}
+
+func (ib *iptablesBackend) checkRules(conf *FirewallNetConf, result *current.Result, ipt *iptables.IPTables, proto iptables.Protocol) error {
+	rules := make([][]string, 0)
+	for _, ip := range result.IPs {
+		if protoForIP(ip.Address) == proto {
+			rules = append(rules, getPrivChainRules(ipString(ip.Address))...)
+		}
+	}
+
+	if len(rules) <= 0 {
+		return nil
+	}
+
+	// Ensure our private chains exist
+	if err := ensureChain(ipt, "filter", ib.privChainName); err != nil {
+		return err
+	}
+	if err := ensureChain(ipt, "filter", ib.adminChainName); err != nil {
+		return err
+	}
+
+	// Ensure our filter rule exists in the forward chain
+	privRule := generateFilterRule(ib.privChainName)
+	privExists, err := ipt.Exists("filter", "FORWARD", privRule...)
+	if err != nil {
+		return err
+	}
+	if !privExists {
+		return fmt.Errorf("expected %v rule %v not found", "FORWARD", privRule)
+	}
+
+	// Ensure our admin override chain rule exists in our private chain
+	adminRule := generateFilterRule(ib.adminChainName)
+	adminExists, err := ipt.Exists("filter", ib.privChainName, adminRule...)
+	if err != nil {
+		return err
+	}
+	if !adminExists {
+		return fmt.Errorf("expected %v rule %v not found", ib.privChainName, adminRule)
+	}
+
+	// ensure rules for this IP address exist
+	for _, rule := range rules {
+		// Ensure our rule exists in our private chain
+		exists, err := ipt.Exists("filter", ib.privChainName, rule...)
+		if err != nil {
+			return err
+		}
+		if !exists {
+			return fmt.Errorf("expected rule %v not found", rule)
+		}
+	}
+
+	return nil
+}
+
+func findProtos(conf *FirewallNetConf) []iptables.Protocol {
+	protos := []iptables.Protocol{iptables.ProtocolIPv4, iptables.ProtocolIPv6}
+	if conf.PrevResult != nil {
+		// If PrevResult is given, scan all IP addresses to figure out
+		// which IP versions to use
+		protos = []iptables.Protocol{}
+		result, _ := current.NewResultFromResult(conf.PrevResult)
+		for _, addr := range result.IPs {
+			if addr.Address.IP.To4() != nil {
+				protos = append(protos, iptables.ProtocolIPv4)
+			} else {
+				protos = append(protos, iptables.ProtocolIPv6)
+			}
+		}
+	}
+	return protos
+}
+
+type iptablesBackend struct {
+	protos         map[iptables.Protocol]*iptables.IPTables
+	privChainName  string
+	adminChainName string
+	ifName         string
+}
+
+// iptablesBackend implements the FirewallBackend interface
+var _ FirewallBackend = &iptablesBackend{}
+
+func newIptablesBackend(conf *FirewallNetConf) (FirewallBackend, error) {
+	adminChainName := conf.IptablesAdminChainName
+	if adminChainName == "" {
+		adminChainName = "CNI-ADMIN"
+	}
+
+	backend := &iptablesBackend{
+		privChainName:  "CNI-FORWARD",
+		adminChainName: adminChainName,
+		protos:         make(map[iptables.Protocol]*iptables.IPTables),
+	}
+
+	for _, proto := range []iptables.Protocol{iptables.ProtocolIPv4, iptables.ProtocolIPv6} {
+		ipt, err := iptables.NewWithProtocol(proto)
+		if err != nil {
+			return nil, fmt.Errorf("could not initialize iptables protocol %v: %v", proto, err)
+		}
+		backend.protos[proto] = ipt
+	}
+
+	return backend, nil
+}
+
+func (ib *iptablesBackend) Add(conf *FirewallNetConf, result *current.Result) error {
+	for proto, ipt := range ib.protos {
+		if err := ib.addRules(conf, result, ipt, proto); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (ib *iptablesBackend) Del(conf *FirewallNetConf, result *current.Result) error {
+	for proto, ipt := range ib.protos {
+		ib.delRules(conf, result, ipt, proto)
+	}
+	return nil
+}
+
+func (ib *iptablesBackend) Check(conf *FirewallNetConf, result *current.Result) error {
+	for proto, ipt := range ib.protos {
+		if err := ib.checkRules(conf, result, ipt, proto); err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/godbus/dbus/.travis.yml b/vendor/github.com/godbus/dbus/.travis.yml
new file mode 100644
index 000000000..2e1bbb78c
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/.travis.yml
@@ -0,0 +1,40 @@
+dist: precise
+language: go
+go_import_path: github.com/godbus/dbus
+sudo: true
+
+go:
+  - 1.6.3
+  - 1.7.3
+  - tip
+
+env:
+  global:
+  matrix:
+   - TARGET=amd64
+   - TARGET=arm64
+   - TARGET=arm
+   - TARGET=386
+   - TARGET=ppc64le
+
+matrix:
+  fast_finish: true
+  allow_failures:
+    - go: tip
+  exclude:
+  - go: tip
+    env: TARGET=arm
+  - go: tip
+    env: TARGET=arm64
+  - go: tip
+    env: TARGET=386
+  - go: tip
+    env: TARGET=ppc64le
+
+addons:
+  apt:
+    packages:
+    - dbus
+    - dbus-x11
+
+before_install:
diff --git a/vendor/github.com/godbus/dbus/CONTRIBUTING.md b/vendor/github.com/godbus/dbus/CONTRIBUTING.md
new file mode 100644
index 000000000..c88f9b2bd
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/CONTRIBUTING.md
@@ -0,0 +1,50 @@
+# How to Contribute
+
+## Getting Started
+
+- Fork the repository on GitHub
+- Read the [README](README.markdown) for build and test instructions
+- Play with the project, submit bugs, submit patches!
+
+## Contribution Flow
+
+This is a rough outline of what a contributor's workflow looks like:
+
+- Create a topic branch from where you want to base your work (usually master).
+- Make commits of logical units.
+- Make sure your commit messages are in the proper format (see below).
+- Push your changes to a topic branch in your fork of the repository.
+- Make sure the tests pass, and add any new tests as appropriate.
+- Submit a pull request to the original repository.
+
+Thanks for your contributions!
+
+### Format of the Commit Message
+
+We follow a rough convention for commit messages that is designed to answer two
+questions: what changed and why. The subject line should feature the what and
+the body of the commit should describe the why.
+
+```
+scripts: add the test-cluster command
+
+this uses tmux to setup a test cluster that you can easily kill and
+start for debugging.
+
+Fixes #38
+```
+
+The format can be described more formally as follows:
+
+```
+<subsystem>: <what changed>
+<BLANK LINE>
+<why this change was made>
+<BLANK LINE>
+<footer>
+```
+
+The first line is the subject and should be no longer than 70 characters, the
+second line is always blank, and other lines should be wrapped at 80 characters.
+This allows the message to be easier to read on GitHub as well as in various
+git tools.
diff --git a/vendor/github.com/godbus/dbus/LICENSE b/vendor/github.com/godbus/dbus/LICENSE
new file mode 100644
index 000000000..670d88fca
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2013, Georg Reinke (<guelfey at gmail dot com>), Google
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/godbus/dbus/MAINTAINERS b/vendor/github.com/godbus/dbus/MAINTAINERS
new file mode 100644
index 000000000..27618c9cd
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/MAINTAINERS
@@ -0,0 +1,3 @@
+Brandon Philips <brandon@ifup.org> (@philips)
+Brian Waldon <brian@waldon.cc> (@bcwaldon)
+John Southworth <jsouthwo@brocade.com> (@jsouthworth)
diff --git a/vendor/github.com/godbus/dbus/README.markdown b/vendor/github.com/godbus/dbus/README.markdown
new file mode 100644
index 000000000..d37f4e2ed
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/README.markdown
@@ -0,0 +1,44 @@
+[![Build Status](https://travis-ci.org/godbus/dbus.svg?branch=master)](https://travis-ci.org/godbus/dbus)
+
+dbus
+----
+
+dbus is a simple library that implements native Go client bindings for the
+D-Bus message bus system.
+
+### Features
+
+* Complete native implementation of the D-Bus message protocol
+* Go-like API (channels for signals / asynchronous method calls, Goroutine-safe connections)
+* Subpackages that help with the introspection / property interfaces
+
+### Installation
+
+This packages requires Go 1.1. If you installed it and set up your GOPATH, just run:
+
+```
+go get github.com/godbus/dbus
+```
+
+If you want to use the subpackages, you can install them the same way.
+
+### Usage
+
+The complete package documentation and some simple examples are available at
+[godoc.org](http://godoc.org/github.com/godbus/dbus). Also, the
+[_examples](https://github.com/godbus/dbus/tree/master/_examples) directory
+gives a short overview over the basic usage. 
+
+#### Projects using godbus
+- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
+- [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API.
+
+Please note that the API is considered unstable for now and may change without
+further notice.
+
+### License
+
+go.dbus is available under the Simplified BSD License; see LICENSE for the full
+text.
+
+Nearly all of the credit for this library goes to github.com/guelfey/go.dbus.
diff --git a/vendor/github.com/godbus/dbus/auth.go b/vendor/github.com/godbus/dbus/auth.go
new file mode 100644
index 000000000..b0dcb54e6
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/auth.go
@@ -0,0 +1,252 @@
+package dbus
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"io"
+	"os"
+	"strconv"
+)
+
+// AuthStatus represents the Status of an authentication mechanism.
+type AuthStatus byte
+
+const (
+	// AuthOk signals that authentication is finished; the next command
+	// from the server should be an OK.
+	AuthOk AuthStatus = iota
+
+	// AuthContinue signals that additional data is needed; the next command
+	// from the server should be a DATA.
+	AuthContinue
+
+	// AuthError signals an error; the server sent invalid data or some
+	// other unexpected thing happened and the current authentication
+	// process should be aborted.
+	AuthError
+)
+
+type authState byte
+
+const (
+	waitingForData authState = iota
+	waitingForOk
+	waitingForReject
+)
+
+// Auth defines the behaviour of an authentication mechanism.
+type Auth interface {
+	// Return the name of the mechnism, the argument to the first AUTH command
+	// and the next status.
+	FirstData() (name, resp []byte, status AuthStatus)
+
+	// Process the given DATA command, and return the argument to the DATA
+	// command and the next status. If len(resp) == 0, no DATA command is sent.
+	HandleData(data []byte) (resp []byte, status AuthStatus)
+}
+
+// Auth authenticates the connection, trying the given list of authentication
+// mechanisms (in that order). If nil is passed, the EXTERNAL and
+// DBUS_COOKIE_SHA1 mechanisms are tried for the current user. For private
+// connections, this method must be called before sending any messages to the
+// bus. Auth must not be called on shared connections.
+func (conn *Conn) Auth(methods []Auth) error {
+	if methods == nil {
+		uid := strconv.Itoa(os.Getuid())
+		methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())}
+	}
+	in := bufio.NewReader(conn.transport)
+	err := conn.transport.SendNullByte()
+	if err != nil {
+		return err
+	}
+	err = authWriteLine(conn.transport, []byte("AUTH"))
+	if err != nil {
+		return err
+	}
+	s, err := authReadLine(in)
+	if err != nil {
+		return err
+	}
+	if len(s) < 2 || !bytes.Equal(s[0], []byte("REJECTED")) {
+		return errors.New("dbus: authentication protocol error")
+	}
+	s = s[1:]
+	for _, v := range s {
+		for _, m := range methods {
+			if name, data, status := m.FirstData(); bytes.Equal(v, name) {
+				var ok bool
+				err = authWriteLine(conn.transport, []byte("AUTH"), []byte(v), data)
+				if err != nil {
+					return err
+				}
+				switch status {
+				case AuthOk:
+					err, ok = conn.tryAuth(m, waitingForOk, in)
+				case AuthContinue:
+					err, ok = conn.tryAuth(m, waitingForData, in)
+				default:
+					panic("dbus: invalid authentication status")
+				}
+				if err != nil {
+					return err
+				}
+				if ok {
+					if conn.transport.SupportsUnixFDs() {
+						err = authWriteLine(conn, []byte("NEGOTIATE_UNIX_FD"))
+						if err != nil {
+							return err
+						}
+						line, err := authReadLine(in)
+						if err != nil {
+							return err
+						}
+						switch {
+						case bytes.Equal(line[0], []byte("AGREE_UNIX_FD")):
+							conn.EnableUnixFDs()
+							conn.unixFD = true
+						case bytes.Equal(line[0], []byte("ERROR")):
+						default:
+							return errors.New("dbus: authentication protocol error")
+						}
+					}
+					err = authWriteLine(conn.transport, []byte("BEGIN"))
+					if err != nil {
+						return err
+					}
+					go conn.inWorker()
+					return nil
+				}
+			}
+		}
+	}
+	return errors.New("dbus: authentication failed")
+}
+
+// tryAuth tries to authenticate with m as the mechanism, using state as the
+// initial authState and in for reading input. It returns (nil, true) on
+// success, (nil, false) on a REJECTED and (someErr, false) if some other
+// error occured.
+func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) {
+	for {
+		s, err := authReadLine(in)
+		if err != nil {
+			return err, false
+		}
+		switch {
+		case state == waitingForData && string(s[0]) == "DATA":
+			if len(s) != 2 {
+				err = authWriteLine(conn.transport, []byte("ERROR"))
+				if err != nil {
+					return err, false
+				}
+				continue
+			}
+			data, status := m.HandleData(s[1])
+			switch status {
+			case AuthOk, AuthContinue:
+				if len(data) != 0 {
+					err = authWriteLine(conn.transport, []byte("DATA"), data)
+					if err != nil {
+						return err, false
+					}
+				}
+				if status == AuthOk {
+					state = waitingForOk
+				}
+			case AuthError:
+				err = authWriteLine(conn.transport, []byte("ERROR"))
+				if err != nil {
+					return err, false
+				}
+			}
+		case state == waitingForData && string(s[0]) == "REJECTED":
+			return nil, false
+		case state == waitingForData && string(s[0]) == "ERROR":
+			err = authWriteLine(conn.transport, []byte("CANCEL"))
+			if err != nil {
+				return err, false
+			}
+			state = waitingForReject
+		case state == waitingForData && string(s[0]) == "OK":
+			if len(s) != 2 {
+				err = authWriteLine(conn.transport, []byte("CANCEL"))
+				if err != nil {
+					return err, false
+				}
+				state = waitingForReject
+			}
+			conn.uuid = string(s[1])
+			return nil, true
+		case state == waitingForData:
+			err = authWriteLine(conn.transport, []byte("ERROR"))
+			if err != nil {
+				return err, false
+			}
+		case state == waitingForOk && string(s[0]) == "OK":
+			if len(s) != 2 {
+				err = authWriteLine(conn.transport, []byte("CANCEL"))
+				if err != nil {
+					return err, false
+				}
+				state = waitingForReject
+			}
+			conn.uuid = string(s[1])
+			return nil, true
+		case state == waitingForOk && string(s[0]) == "REJECTED":
+			return nil, false
+		case state == waitingForOk && (string(s[0]) == "DATA" ||
+			string(s[0]) == "ERROR"):
+
+			err = authWriteLine(conn.transport, []byte("CANCEL"))
+			if err != nil {
+				return err, false
+			}
+			state = waitingForReject
+		case state == waitingForOk:
+			err = authWriteLine(conn.transport, []byte("ERROR"))
+			if err != nil {
+				return err, false
+			}
+		case state == waitingForReject && string(s[0]) == "REJECTED":
+			return nil, false
+		case state == waitingForReject:
+			return errors.New("dbus: authentication protocol error"), false
+		default:
+			panic("dbus: invalid auth state")
+		}
+	}
+}
+
+// authReadLine reads a line and separates it into its fields.
+func authReadLine(in *bufio.Reader) ([][]byte, error) {
+	data, err := in.ReadBytes('\n')
+	if err != nil {
+		return nil, err
+	}
+	data = bytes.TrimSuffix(data, []byte("\r\n"))
+	return bytes.Split(data, []byte{' '}), nil
+}
+
+// authWriteLine writes the given line in the authentication protocol format
+// (elements of data separated by a " " and terminated by "\r\n").
+func authWriteLine(out io.Writer, data ...[]byte) error {
+	buf := make([]byte, 0)
+	for i, v := range data {
+		buf = append(buf, v...)
+		if i != len(data)-1 {
+			buf = append(buf, ' ')
+		}
+	}
+	buf = append(buf, '\r')
+	buf = append(buf, '\n')
+	n, err := out.Write(buf)
+	if err != nil {
+		return err
+	}
+	if n != len(buf) {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
diff --git a/vendor/github.com/godbus/dbus/auth_external.go b/vendor/github.com/godbus/dbus/auth_external.go
new file mode 100644
index 000000000..7e376d3ef
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/auth_external.go
@@ -0,0 +1,26 @@
+package dbus
+
+import (
+	"encoding/hex"
+)
+
+// AuthExternal returns an Auth that authenticates as the given user with the
+// EXTERNAL mechanism.
+func AuthExternal(user string) Auth {
+	return authExternal{user}
+}
+
+// AuthExternal implements the EXTERNAL authentication mechanism.
+type authExternal struct {
+	user string
+}
+
+func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) {
+	b := make([]byte, 2*len(a.user))
+	hex.Encode(b, []byte(a.user))
+	return []byte("EXTERNAL"), b, AuthOk
+}
+
+func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) {
+	return nil, AuthError
+}
diff --git a/vendor/github.com/godbus/dbus/auth_sha1.go b/vendor/github.com/godbus/dbus/auth_sha1.go
new file mode 100644
index 000000000..df15b4611
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/auth_sha1.go
@@ -0,0 +1,102 @@
+package dbus
+
+import (
+	"bufio"
+	"bytes"
+	"crypto/rand"
+	"crypto/sha1"
+	"encoding/hex"
+	"os"
+)
+
+// AuthCookieSha1 returns an Auth that authenticates as the given user with the
+// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home
+// directory of the user.
+func AuthCookieSha1(user, home string) Auth {
+	return authCookieSha1{user, home}
+}
+
+type authCookieSha1 struct {
+	user, home string
+}
+
+func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) {
+	b := make([]byte, 2*len(a.user))
+	hex.Encode(b, []byte(a.user))
+	return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue
+}
+
+func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) {
+	challenge := make([]byte, len(data)/2)
+	_, err := hex.Decode(challenge, data)
+	if err != nil {
+		return nil, AuthError
+	}
+	b := bytes.Split(challenge, []byte{' '})
+	if len(b) != 3 {
+		return nil, AuthError
+	}
+	context := b[0]
+	id := b[1]
+	svchallenge := b[2]
+	cookie := a.getCookie(context, id)
+	if cookie == nil {
+		return nil, AuthError
+	}
+	clchallenge := a.generateChallenge()
+	if clchallenge == nil {
+		return nil, AuthError
+	}
+	hash := sha1.New()
+	hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'}))
+	hexhash := make([]byte, 2*hash.Size())
+	hex.Encode(hexhash, hash.Sum(nil))
+	data = append(clchallenge, ' ')
+	data = append(data, hexhash...)
+	resp := make([]byte, 2*len(data))
+	hex.Encode(resp, data)
+	return resp, AuthOk
+}
+
+// getCookie searches for the cookie identified by id in context and returns
+// the cookie content or nil. (Since HandleData can't return a specific error,
+// but only whether an error occured, this function also doesn't bother to
+// return an error.)
+func (a authCookieSha1) getCookie(context, id []byte) []byte {
+	file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context))
+	if err != nil {
+		return nil
+	}
+	defer file.Close()
+	rd := bufio.NewReader(file)
+	for {
+		line, err := rd.ReadBytes('\n')
+		if err != nil {
+			return nil
+		}
+		line = line[:len(line)-1]
+		b := bytes.Split(line, []byte{' '})
+		if len(b) != 3 {
+			return nil
+		}
+		if bytes.Equal(b[0], id) {
+			return b[2]
+		}
+	}
+}
+
+// generateChallenge returns a random, hex-encoded challenge, or nil on error
+// (see above).
+func (a authCookieSha1) generateChallenge() []byte {
+	b := make([]byte, 16)
+	n, err := rand.Read(b)
+	if err != nil {
+		return nil
+	}
+	if n != 16 {
+		return nil
+	}
+	enc := make([]byte, 32)
+	hex.Encode(enc, b)
+	return enc
+}
diff --git a/vendor/github.com/godbus/dbus/call.go b/vendor/github.com/godbus/dbus/call.go
new file mode 100644
index 000000000..ba6e73f60
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/call.go
@@ -0,0 +1,36 @@
+package dbus
+
+import (
+	"errors"
+)
+
+// Call represents a pending or completed method call.
+type Call struct {
+	Destination string
+	Path        ObjectPath
+	Method      string
+	Args        []interface{}
+
+	// Strobes when the call is complete.
+	Done chan *Call
+
+	// After completion, the error status. If this is non-nil, it may be an
+	// error message from the peer (with Error as its type) or some other error.
+	Err error
+
+	// Holds the response once the call is done.
+	Body []interface{}
+}
+
+var errSignature = errors.New("dbus: mismatched signature")
+
+// Store stores the body of the reply into the provided pointers. It returns
+// an error if the signatures of the body and retvalues don't match, or if
+// the error status is not nil.
+func (c *Call) Store(retvalues ...interface{}) error {
+	if c.Err != nil {
+		return c.Err
+	}
+
+	return Store(c.Body, retvalues...)
+}
diff --git a/vendor/github.com/godbus/dbus/conn.go b/vendor/github.com/godbus/dbus/conn.go
new file mode 100644
index 000000000..d4417d0c7
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/conn.go
@@ -0,0 +1,767 @@
+package dbus
+
+import (
+	"errors"
+	"io"
+	"os"
+	"reflect"
+	"strings"
+	"sync"
+)
+
+var (
+	systemBus     *Conn
+	systemBusLck  sync.Mutex
+	sessionBus    *Conn
+	sessionBusLck sync.Mutex
+	sessionEnvLck sync.Mutex
+)
+
+// ErrClosed is the error returned by calls on a closed connection.
+var ErrClosed = errors.New("dbus: connection closed by user")
+
+// Conn represents a connection to a message bus (usually, the system or
+// session bus).
+//
+// Connections are either shared or private. Shared connections
+// are shared between calls to the functions that return them. As a result,
+// the methods Close, Auth and Hello must not be called on them.
+//
+// Multiple goroutines may invoke methods on a connection simultaneously.
+type Conn struct {
+	transport
+
+	busObj BusObject
+	unixFD bool
+	uuid   string
+
+	names *nameTracker
+
+	serialGen *serialGenerator
+
+	calls *callTracker
+
+	handler Handler
+
+	outHandler *outputHandler
+
+	signalHandler SignalHandler
+
+	eavesdropped    chan<- *Message
+	eavesdroppedLck sync.Mutex
+}
+
+// SessionBus returns a shared connection to the session bus, connecting to it
+// if not already done.
+func SessionBus() (conn *Conn, err error) {
+	sessionBusLck.Lock()
+	defer sessionBusLck.Unlock()
+	if sessionBus != nil {
+		return sessionBus, nil
+	}
+	defer func() {
+		if conn != nil {
+			sessionBus = conn
+		}
+	}()
+	conn, err = SessionBusPrivate()
+	if err != nil {
+		return
+	}
+	if err = conn.Auth(nil); err != nil {
+		conn.Close()
+		conn = nil
+		return
+	}
+	if err = conn.Hello(); err != nil {
+		conn.Close()
+		conn = nil
+	}
+	return
+}
+
+func getSessionBusAddress() (string, error) {
+	sessionEnvLck.Lock()
+	defer sessionEnvLck.Unlock()
+	address := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
+	if address != "" && address != "autolaunch:" {
+		return address, nil
+	}
+	return getSessionBusPlatformAddress()
+}
+
+// SessionBusPrivate returns a new private connection to the session bus.
+func SessionBusPrivate() (*Conn, error) {
+	address, err := getSessionBusAddress()
+	if err != nil {
+		return nil, err
+	}
+
+	return Dial(address)
+}
+
+// SessionBusPrivate returns a new private connection to the session bus.
+func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
+	address, err := getSessionBusAddress()
+	if err != nil {
+		return nil, err
+	}
+	return DialHandler(address, handler, signalHandler)
+}
+
+// SystemBus returns a shared connection to the system bus, connecting to it if
+// not already done.
+func SystemBus() (conn *Conn, err error) {
+	systemBusLck.Lock()
+	defer systemBusLck.Unlock()
+	if systemBus != nil {
+		return systemBus, nil
+	}
+	defer func() {
+		if conn != nil {
+			systemBus = conn
+		}
+	}()
+	conn, err = SystemBusPrivate()
+	if err != nil {
+		return
+	}
+	if err = conn.Auth(nil); err != nil {
+		conn.Close()
+		conn = nil
+		return
+	}
+	if err = conn.Hello(); err != nil {
+		conn.Close()
+		conn = nil
+	}
+	return
+}
+
+// SystemBusPrivate returns a new private connection to the system bus.
+func SystemBusPrivate() (*Conn, error) {
+	return Dial(getSystemBusPlatformAddress())
+}
+
+// SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers.
+func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
+	return DialHandler(getSystemBusPlatformAddress(), handler, signalHandler)
+}
+
+// Dial establishes a new private connection to the message bus specified by address.
+func Dial(address string) (*Conn, error) {
+	tr, err := getTransport(address)
+	if err != nil {
+		return nil, err
+	}
+	return newConn(tr, NewDefaultHandler(), NewDefaultSignalHandler())
+}
+
+// DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers.
+func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
+	tr, err := getTransport(address)
+	if err != nil {
+		return nil, err
+	}
+	return newConn(tr, handler, signalHandler)
+}
+
+// NewConn creates a new private *Conn from an already established connection.
+func NewConn(conn io.ReadWriteCloser) (*Conn, error) {
+	return NewConnHandler(conn, NewDefaultHandler(), NewDefaultSignalHandler())
+}
+
+// NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers.
+func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) {
+	return newConn(genericTransport{conn}, handler, signalHandler)
+}
+
+// newConn creates a new *Conn from a transport.
+func newConn(tr transport, handler Handler, signalHandler SignalHandler) (*Conn, error) {
+	conn := new(Conn)
+	conn.transport = tr
+	conn.calls = newCallTracker()
+	conn.handler = handler
+	conn.signalHandler = signalHandler
+	conn.outHandler = &outputHandler{conn: conn}
+	conn.serialGen = newSerialGenerator()
+	conn.names = newNameTracker()
+	conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
+	return conn, nil
+}
+
+// BusObject returns the object owned by the bus daemon which handles
+// administrative requests.
+func (conn *Conn) BusObject() BusObject {
+	return conn.busObj
+}
+
+// Close closes the connection. Any blocked operations will return with errors
+// and the channels passed to Eavesdrop and Signal are closed. This method must
+// not be called on shared connections.
+func (conn *Conn) Close() error {
+	conn.outHandler.close()
+	if term, ok := conn.signalHandler.(Terminator); ok {
+		term.Terminate()
+	}
+
+	if term, ok := conn.handler.(Terminator); ok {
+		term.Terminate()
+	}
+
+	conn.eavesdroppedLck.Lock()
+	if conn.eavesdropped != nil {
+		close(conn.eavesdropped)
+	}
+	conn.eavesdroppedLck.Unlock()
+
+	return conn.transport.Close()
+}
+
+// Eavesdrop causes conn to send all incoming messages to the given channel
+// without further processing. Method replies, errors and signals will not be
+// sent to the appropiate channels and method calls will not be handled. If nil
+// is passed, the normal behaviour is restored.
+//
+// The caller has to make sure that ch is sufficiently buffered;
+// if a message arrives when a write to ch is not possible, the message is
+// discarded.
+func (conn *Conn) Eavesdrop(ch chan<- *Message) {
+	conn.eavesdroppedLck.Lock()
+	conn.eavesdropped = ch
+	conn.eavesdroppedLck.Unlock()
+}
+
+// getSerial returns an unused serial.
+func (conn *Conn) getSerial() uint32 {
+	return conn.serialGen.getSerial()
+}
+
+// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be
+// called after authentication, but before sending any other messages to the
+// bus. Hello must not be called for shared connections.
+func (conn *Conn) Hello() error {
+	var s string
+	err := conn.busObj.Call("org.freedesktop.DBus.Hello", 0).Store(&s)
+	if err != nil {
+		return err
+	}
+	conn.names.acquireUniqueConnectionName(s)
+	return nil
+}
+
+// inWorker runs in an own goroutine, reading incoming messages from the
+// transport and dispatching them appropiately.
+func (conn *Conn) inWorker() {
+	for {
+		msg, err := conn.ReadMessage()
+		if err != nil {
+			if _, ok := err.(InvalidMessageError); !ok {
+				// Some read error occured (usually EOF); we can't really do
+				// anything but to shut down all stuff and returns errors to all
+				// pending replies.
+				conn.Close()
+				conn.calls.finalizeAllWithError(err)
+				return
+			}
+			// invalid messages are ignored
+			continue
+		}
+		conn.eavesdroppedLck.Lock()
+		if conn.eavesdropped != nil {
+			select {
+			case conn.eavesdropped <- msg:
+			default:
+			}
+			conn.eavesdroppedLck.Unlock()
+			continue
+		}
+		conn.eavesdroppedLck.Unlock()
+		dest, _ := msg.Headers[FieldDestination].value.(string)
+		found := dest == "" ||
+			!conn.names.uniqueNameIsKnown() ||
+			conn.names.isKnownName(dest)
+		if !found {
+			// Eavesdropped a message, but no channel for it is registered.
+			// Ignore it.
+			continue
+		}
+		switch msg.Type {
+		case TypeError:
+			conn.serialGen.retireSerial(conn.calls.handleDBusError(msg))
+		case TypeMethodReply:
+			conn.serialGen.retireSerial(conn.calls.handleReply(msg))
+		case TypeSignal:
+			conn.handleSignal(msg)
+		case TypeMethodCall:
+			go conn.handleCall(msg)
+		}
+
+	}
+}
+
+func (conn *Conn) handleSignal(msg *Message) {
+	iface := msg.Headers[FieldInterface].value.(string)
+	member := msg.Headers[FieldMember].value.(string)
+	// as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
+	// sender is optional for signals.
+	sender, _ := msg.Headers[FieldSender].value.(string)
+	if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
+		if member == "NameLost" {
+			// If we lost the name on the bus, remove it from our
+			// tracking list.
+			name, ok := msg.Body[0].(string)
+			if !ok {
+				panic("Unable to read the lost name")
+			}
+			conn.names.loseName(name)
+		} else if member == "NameAcquired" {
+			// If we acquired the name on the bus, add it to our
+			// tracking list.
+			name, ok := msg.Body[0].(string)
+			if !ok {
+				panic("Unable to read the acquired name")
+			}
+			conn.names.acquireName(name)
+		}
+	}
+	signal := &Signal{
+		Sender: sender,
+		Path:   msg.Headers[FieldPath].value.(ObjectPath),
+		Name:   iface + "." + member,
+		Body:   msg.Body,
+	}
+	conn.signalHandler.DeliverSignal(iface, member, signal)
+}
+
+// Names returns the list of all names that are currently owned by this
+// connection. The slice is always at least one element long, the first element
+// being the unique name of the connection.
+func (conn *Conn) Names() []string {
+	return conn.names.listKnownNames()
+}
+
+// Object returns the object identified by the given destination name and path.
+func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
+	return &Object{conn, dest, path}
+}
+
+// outWorker runs in an own goroutine, encoding and sending messages that are
+// sent to conn.out.
+func (conn *Conn) sendMessage(msg *Message) {
+	conn.sendMessageAndIfClosed(msg, func() {})
+}
+
+func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
+	err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
+	conn.calls.handleSendError(msg, err)
+	if err != nil {
+		conn.serialGen.retireSerial(msg.serial)
+	} else if msg.Type != TypeMethodCall {
+		conn.serialGen.retireSerial(msg.serial)
+	}
+}
+
+// Send sends the given message to the message bus. You usually don't need to
+// use this; use the higher-level equivalents (Call / Go, Emit and Export)
+// instead. If msg is a method call and NoReplyExpected is not set, a non-nil
+// call is returned and the same value is sent to ch (which must be buffered)
+// once the call is complete. Otherwise, ch is ignored and a Call structure is
+// returned of which only the Err member is valid.
+func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
+	var call *Call
+
+	msg.serial = conn.getSerial()
+	if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
+		if ch == nil {
+			ch = make(chan *Call, 5)
+		} else if cap(ch) == 0 {
+			panic("dbus: unbuffered channel passed to (*Conn).Send")
+		}
+		call = new(Call)
+		call.Destination, _ = msg.Headers[FieldDestination].value.(string)
+		call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath)
+		iface, _ := msg.Headers[FieldInterface].value.(string)
+		member, _ := msg.Headers[FieldMember].value.(string)
+		call.Method = iface + "." + member
+		call.Args = msg.Body
+		call.Done = ch
+		conn.calls.track(msg.serial, call)
+		conn.sendMessageAndIfClosed(msg, func() {
+			call.Err = ErrClosed
+			call.Done <- call
+		})
+	} else {
+		call = &Call{Err: nil}
+		conn.sendMessageAndIfClosed(msg, func() {
+			call = &Call{Err: ErrClosed}
+		})
+	}
+	return call
+}
+
+// sendError creates an error message corresponding to the parameters and sends
+// it to conn.out.
+func (conn *Conn) sendError(err error, dest string, serial uint32) {
+	var e *Error
+	switch em := err.(type) {
+	case Error:
+		e = &em
+	case *Error:
+		e = em
+	case DBusError:
+		name, body := em.DBusError()
+		e = NewError(name, body)
+	default:
+		e = MakeFailedError(err)
+	}
+	msg := new(Message)
+	msg.Type = TypeError
+	msg.serial = conn.getSerial()
+	msg.Headers = make(map[HeaderField]Variant)
+	if dest != "" {
+		msg.Headers[FieldDestination] = MakeVariant(dest)
+	}
+	msg.Headers[FieldErrorName] = MakeVariant(e.Name)
+	msg.Headers[FieldReplySerial] = MakeVariant(serial)
+	msg.Body = e.Body
+	if len(e.Body) > 0 {
+		msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
+	}
+	conn.sendMessage(msg)
+}
+
+// sendReply creates a method reply message corresponding to the parameters and
+// sends it to conn.out.
+func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
+	msg := new(Message)
+	msg.Type = TypeMethodReply
+	msg.serial = conn.getSerial()
+	msg.Headers = make(map[HeaderField]Variant)
+	if dest != "" {
+		msg.Headers[FieldDestination] = MakeVariant(dest)
+	}
+	msg.Headers[FieldReplySerial] = MakeVariant(serial)
+	msg.Body = values
+	if len(values) > 0 {
+		msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
+	}
+	conn.sendMessage(msg)
+}
+
+func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) {
+	if !isDefaultSignalHandler(conn.signalHandler) {
+		return
+	}
+	handler := conn.signalHandler.(*defaultSignalHandler)
+	fn(handler, ch)
+}
+
+// Signal registers the given channel to be passed all received signal messages.
+// The caller has to make sure that ch is sufficiently buffered; if a message
+// arrives when a write to c is not possible, it is discarded.
+//
+// Multiple of these channels can be registered at the same time.
+//
+// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
+// channel for eavesdropped messages, this channel receives all signals, and
+// none of the channels passed to Signal will receive any signals.
+func (conn *Conn) Signal(ch chan<- *Signal) {
+	conn.defaultSignalAction((*defaultSignalHandler).addSignal, ch)
+}
+
+// RemoveSignal removes the given channel from the list of the registered channels.
+func (conn *Conn) RemoveSignal(ch chan<- *Signal) {
+	conn.defaultSignalAction((*defaultSignalHandler).removeSignal, ch)
+}
+
+// SupportsUnixFDs returns whether the underlying transport supports passing of
+// unix file descriptors. If this is false, method calls containing unix file
+// descriptors will return an error and emitted signals containing them will
+// not be sent.
+func (conn *Conn) SupportsUnixFDs() bool {
+	return conn.unixFD
+}
+
+// Error represents a D-Bus message of type Error.
+type Error struct {
+	Name string
+	Body []interface{}
+}
+
+func NewError(name string, body []interface{}) *Error {
+	return &Error{name, body}
+}
+
+func (e Error) Error() string {
+	if len(e.Body) >= 1 {
+		s, ok := e.Body[0].(string)
+		if ok {
+			return s
+		}
+	}
+	return e.Name
+}
+
+// Signal represents a D-Bus message of type Signal. The name member is given in
+// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost.
+type Signal struct {
+	Sender string
+	Path   ObjectPath
+	Name   string
+	Body   []interface{}
+}
+
+// transport is a D-Bus transport.
+type transport interface {
+	// Read and Write raw data (for example, for the authentication protocol).
+	io.ReadWriteCloser
+
+	// Send the initial null byte used for the EXTERNAL mechanism.
+	SendNullByte() error
+
+	// Returns whether this transport supports passing Unix FDs.
+	SupportsUnixFDs() bool
+
+	// Signal the transport that Unix FD passing is enabled for this connection.
+	EnableUnixFDs()
+
+	// Read / send a message, handling things like Unix FDs.
+	ReadMessage() (*Message, error)
+	SendMessage(*Message) error
+}
+
+var (
+	transports = make(map[string]func(string) (transport, error))
+)
+
+func getTransport(address string) (transport, error) {
+	var err error
+	var t transport
+
+	addresses := strings.Split(address, ";")
+	for _, v := range addresses {
+		i := strings.IndexRune(v, ':')
+		if i == -1 {
+			err = errors.New("dbus: invalid bus address (no transport)")
+			continue
+		}
+		f := transports[v[:i]]
+		if f == nil {
+			err = errors.New("dbus: invalid bus address (invalid or unsupported transport)")
+			continue
+		}
+		t, err = f(v[i+1:])
+		if err == nil {
+			return t, nil
+		}
+	}
+	return nil, err
+}
+
+// dereferenceAll returns a slice that, assuming that vs is a slice of pointers
+// of arbitrary types, containes the values that are obtained from dereferencing
+// all elements in vs.
+func dereferenceAll(vs []interface{}) []interface{} {
+	for i := range vs {
+		v := reflect.ValueOf(vs[i])
+		v = v.Elem()
+		vs[i] = v.Interface()
+	}
+	return vs
+}
+
+// getKey gets a key from a the list of keys. Returns "" on error / not found...
+func getKey(s, key string) string {
+	for _, keyEqualsValue := range strings.Split(s, ",") {
+		keyValue := strings.SplitN(keyEqualsValue, "=", 2)
+		if len(keyValue) == 2 && keyValue[0] == key {
+			return keyValue[1]
+		}
+	}
+	return ""
+}
+
+type outputHandler struct {
+	conn    *Conn
+	sendLck sync.Mutex
+	closed  struct {
+		isClosed bool
+		lck      sync.RWMutex
+	}
+}
+
+func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error {
+	h.closed.lck.RLock()
+	defer h.closed.lck.RUnlock()
+	if h.closed.isClosed {
+		ifClosed()
+		return nil
+	}
+	h.sendLck.Lock()
+	defer h.sendLck.Unlock()
+	return h.conn.SendMessage(msg)
+}
+
+func (h *outputHandler) close() {
+	h.closed.lck.Lock()
+	defer h.closed.lck.Unlock()
+	h.closed.isClosed = true
+}
+
+type serialGenerator struct {
+	lck        sync.Mutex
+	nextSerial uint32
+	serialUsed map[uint32]bool
+}
+
+func newSerialGenerator() *serialGenerator {
+	return &serialGenerator{
+		serialUsed: map[uint32]bool{0: true},
+		nextSerial: 1,
+	}
+}
+
+func (gen *serialGenerator) getSerial() uint32 {
+	gen.lck.Lock()
+	defer gen.lck.Unlock()
+	n := gen.nextSerial
+	for gen.serialUsed[n] {
+		n++
+	}
+	gen.serialUsed[n] = true
+	gen.nextSerial = n + 1
+	return n
+}
+
+func (gen *serialGenerator) retireSerial(serial uint32) {
+	gen.lck.Lock()
+	defer gen.lck.Unlock()
+	delete(gen.serialUsed, serial)
+}
+
+type nameTracker struct {
+	lck    sync.RWMutex
+	unique string
+	names  map[string]struct{}
+}
+
+func newNameTracker() *nameTracker {
+	return &nameTracker{names: map[string]struct{}{}}
+}
+func (tracker *nameTracker) acquireUniqueConnectionName(name string) {
+	tracker.lck.Lock()
+	defer tracker.lck.Unlock()
+	tracker.unique = name
+}
+func (tracker *nameTracker) acquireName(name string) {
+	tracker.lck.Lock()
+	defer tracker.lck.Unlock()
+	tracker.names[name] = struct{}{}
+}
+func (tracker *nameTracker) loseName(name string) {
+	tracker.lck.Lock()
+	defer tracker.lck.Unlock()
+	delete(tracker.names, name)
+}
+
+func (tracker *nameTracker) uniqueNameIsKnown() bool {
+	tracker.lck.RLock()
+	defer tracker.lck.RUnlock()
+	return tracker.unique != ""
+}
+func (tracker *nameTracker) isKnownName(name string) bool {
+	tracker.lck.RLock()
+	defer tracker.lck.RUnlock()
+	_, ok := tracker.names[name]
+	return ok || name == tracker.unique
+}
+func (tracker *nameTracker) listKnownNames() []string {
+	tracker.lck.RLock()
+	defer tracker.lck.RUnlock()
+	out := make([]string, 0, len(tracker.names)+1)
+	out = append(out, tracker.unique)
+	for k := range tracker.names {
+		out = append(out, k)
+	}
+	return out
+}
+
+type callTracker struct {
+	calls map[uint32]*Call
+	lck   sync.RWMutex
+}
+
+func newCallTracker() *callTracker {
+	return &callTracker{calls: map[uint32]*Call{}}
+}
+
+func (tracker *callTracker) track(sn uint32, call *Call) {
+	tracker.lck.Lock()
+	defer tracker.lck.Unlock()
+	tracker.calls[sn] = call
+}
+
+func (tracker *callTracker) handleReply(msg *Message) uint32 {
+	serial := msg.Headers[FieldReplySerial].value.(uint32)
+	tracker.lck.RLock()
+	c, ok := tracker.calls[serial]
+	tracker.lck.RUnlock()
+	if !ok {
+		return serial
+	}
+	c.Body = msg.Body
+	c.Done <- c
+	tracker.finalize(serial)
+	return serial
+}
+
+func (tracker *callTracker) handleDBusError(msg *Message) uint32 {
+	serial := msg.Headers[FieldReplySerial].value.(uint32)
+	tracker.lck.RLock()
+	c, ok := tracker.calls[serial]
+	tracker.lck.RUnlock()
+	if !ok {
+		return serial
+	}
+	name, _ := msg.Headers[FieldErrorName].value.(string)
+	c.Err = Error{name, msg.Body}
+	c.Done <- c
+	tracker.finalize(serial)
+	return serial
+}
+
+func (tracker *callTracker) handleSendError(msg *Message, err error) {
+	if err == nil {
+		return
+	}
+	tracker.lck.RLock()
+	c, ok := tracker.calls[msg.serial]
+	tracker.lck.RUnlock()
+	if !ok {
+		return
+	}
+	c.Err = err
+	c.Done <- c
+	tracker.finalize(msg.serial)
+}
+
+func (tracker *callTracker) finalize(sn uint32) {
+	tracker.lck.Lock()
+	defer tracker.lck.Unlock()
+	delete(tracker.calls, sn)
+}
+
+func (tracker *callTracker) finalizeAllWithError(err error) {
+	closedCalls := make(map[uint32]*Call)
+	tracker.lck.RLock()
+	for sn, v := range tracker.calls {
+		v.Err = err
+		v.Done <- v
+		closedCalls[sn] = v
+	}
+	tracker.lck.RUnlock()
+	for sn := range closedCalls {
+		tracker.finalize(sn)
+	}
+}
diff --git a/vendor/github.com/godbus/dbus/conn_darwin.go b/vendor/github.com/godbus/dbus/conn_darwin.go
new file mode 100644
index 000000000..c015f80ce
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/conn_darwin.go
@@ -0,0 +1,33 @@
+package dbus
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"os/exec"
+)
+
+const defaultSystemBusAddress = "unix:path=/opt/local/var/run/dbus/system_bus_socket"
+
+func getSessionBusPlatformAddress() (string, error) {
+	cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET")
+	b, err := cmd.CombinedOutput()
+
+	if err != nil {
+		return "", err
+	}
+
+	if len(b) == 0 {
+		return "", errors.New("dbus: couldn't determine address of session bus")
+	}
+
+	return "unix:path=" + string(b[:len(b)-1]), nil
+}
+
+func getSystemBusPlatformAddress() string {
+	address := os.Getenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET")
+	if address != "" {
+		return fmt.Sprintf("unix:path=%s", address)
+	}
+	return defaultSystemBusAddress
+}
diff --git a/vendor/github.com/godbus/dbus/conn_other.go b/vendor/github.com/godbus/dbus/conn_other.go
new file mode 100644
index 000000000..254c9f2ef
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/conn_other.go
@@ -0,0 +1,42 @@
+// +build !darwin
+
+package dbus
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"os"
+	"os/exec"
+)
+
+const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
+
+func getSessionBusPlatformAddress() (string, error) {
+	cmd := exec.Command("dbus-launch")
+	b, err := cmd.CombinedOutput()
+
+	if err != nil {
+		return "", err
+	}
+
+	i := bytes.IndexByte(b, '=')
+	j := bytes.IndexByte(b, '\n')
+
+	if i == -1 || j == -1 {
+		return "", errors.New("dbus: couldn't determine address of session bus")
+	}
+
+	env, addr := string(b[0:i]), string(b[i+1:j])
+	os.Setenv(env, addr)
+
+	return addr, nil
+}
+
+func getSystemBusPlatformAddress() string {
+	address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
+	if address != "" {
+		return fmt.Sprintf("unix:path=%s", address)
+	}
+	return defaultSystemBusAddress
+}
diff --git a/vendor/github.com/godbus/dbus/dbus.go b/vendor/github.com/godbus/dbus/dbus.go
new file mode 100644
index 000000000..c6d0d3ce0
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/dbus.go
@@ -0,0 +1,427 @@
+package dbus
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+)
+
+var (
+	byteType        = reflect.TypeOf(byte(0))
+	boolType        = reflect.TypeOf(false)
+	uint8Type       = reflect.TypeOf(uint8(0))
+	int16Type       = reflect.TypeOf(int16(0))
+	uint16Type      = reflect.TypeOf(uint16(0))
+	intType         = reflect.TypeOf(int(0))
+	uintType        = reflect.TypeOf(uint(0))
+	int32Type       = reflect.TypeOf(int32(0))
+	uint32Type      = reflect.TypeOf(uint32(0))
+	int64Type       = reflect.TypeOf(int64(0))
+	uint64Type      = reflect.TypeOf(uint64(0))
+	float64Type     = reflect.TypeOf(float64(0))
+	stringType      = reflect.TypeOf("")
+	signatureType   = reflect.TypeOf(Signature{""})
+	objectPathType  = reflect.TypeOf(ObjectPath(""))
+	variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
+	interfacesType  = reflect.TypeOf([]interface{}{})
+	interfaceType   = reflect.TypeOf((*interface{})(nil)).Elem()
+	unixFDType      = reflect.TypeOf(UnixFD(0))
+	unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
+)
+
+// An InvalidTypeError signals that a value which cannot be represented in the
+// D-Bus wire format was passed to a function.
+type InvalidTypeError struct {
+	Type reflect.Type
+}
+
+func (e InvalidTypeError) Error() string {
+	return "dbus: invalid type " + e.Type.String()
+}
+
+// Store copies the values contained in src to dest, which must be a slice of
+// pointers. It converts slices of interfaces from src to corresponding structs
+// in dest. An error is returned if the lengths of src and dest or the types of
+// their elements don't match.
+func Store(src []interface{}, dest ...interface{}) error {
+	if len(src) != len(dest) {
+		return errors.New("dbus.Store: length mismatch")
+	}
+
+	for i := range src {
+		if err := storeInterfaces(src[i], dest[i]); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func storeInterfaces(src, dest interface{}) error {
+	return store(reflect.ValueOf(dest), reflect.ValueOf(src))
+}
+
+func store(dest, src reflect.Value) error {
+	if dest.Kind() == reflect.Ptr {
+		return store(dest.Elem(), src)
+	}
+	switch src.Kind() {
+	case reflect.Slice:
+		return storeSlice(dest, src)
+	case reflect.Map:
+		return storeMap(dest, src)
+	default:
+		return storeBase(dest, src)
+	}
+}
+
+func storeBase(dest, src reflect.Value) error {
+	return setDest(dest, src)
+}
+
+func setDest(dest, src reflect.Value) error {
+	if !isVariant(src.Type()) && isVariant(dest.Type()) {
+		//special conversion for dbus.Variant
+		dest.Set(reflect.ValueOf(MakeVariant(src.Interface())))
+		return nil
+	}
+	if isVariant(src.Type()) && !isVariant(dest.Type()) {
+		src = getVariantValue(src)
+	}
+	if !src.Type().ConvertibleTo(dest.Type()) {
+		return fmt.Errorf(
+			"dbus.Store: type mismatch: cannot convert %s to %s",
+			src.Type(), dest.Type())
+	}
+	dest.Set(src.Convert(dest.Type()))
+	return nil
+}
+
+func kindsAreCompatible(dest, src reflect.Type) bool {
+	switch {
+	case isVariant(dest):
+		return true
+	case dest.Kind() == reflect.Interface:
+		return true
+	default:
+		return dest.Kind() == src.Kind()
+	}
+}
+
+func isConvertibleTo(dest, src reflect.Type) bool {
+	switch {
+	case isVariant(dest):
+		return true
+	case dest.Kind() == reflect.Interface:
+		return true
+	case dest.Kind() == reflect.Slice:
+		return src.Kind() == reflect.Slice &&
+			isConvertibleTo(dest.Elem(), src.Elem())
+	case dest.Kind() == reflect.Struct:
+		return src == interfacesType
+	default:
+		return src.ConvertibleTo(dest)
+	}
+}
+
+func storeMap(dest, src reflect.Value) error {
+	switch {
+	case !kindsAreCompatible(dest.Type(), src.Type()):
+		return fmt.Errorf(
+			"dbus.Store: type mismatch: "+
+				"map: cannot store a value of %s into %s",
+			src.Type(), dest.Type())
+	case isVariant(dest.Type()):
+		return storeMapIntoVariant(dest, src)
+	case dest.Kind() == reflect.Interface:
+		return storeMapIntoInterface(dest, src)
+	case isConvertibleTo(dest.Type().Key(), src.Type().Key()) &&
+		isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
+		return storeMapIntoMap(dest, src)
+	default:
+		return fmt.Errorf(
+			"dbus.Store: type mismatch: "+
+				"map: cannot convert a value of %s into %s",
+			src.Type(), dest.Type())
+	}
+}
+
+func storeMapIntoVariant(dest, src reflect.Value) error {
+	dv := reflect.MakeMap(src.Type())
+	err := store(dv, src)
+	if err != nil {
+		return err
+	}
+	return storeBase(dest, dv)
+}
+
+func storeMapIntoInterface(dest, src reflect.Value) error {
+	var dv reflect.Value
+	if isVariant(src.Type().Elem()) {
+		//Convert variants to interface{} recursively when converting
+		//to interface{}
+		dv = reflect.MakeMap(
+			reflect.MapOf(src.Type().Key(), interfaceType))
+	} else {
+		dv = reflect.MakeMap(src.Type())
+	}
+	err := store(dv, src)
+	if err != nil {
+		return err
+	}
+	return storeBase(dest, dv)
+}
+
+func storeMapIntoMap(dest, src reflect.Value) error {
+	if dest.IsNil() {
+		dest.Set(reflect.MakeMap(dest.Type()))
+	}
+	keys := src.MapKeys()
+	for _, key := range keys {
+		dkey := key.Convert(dest.Type().Key())
+		dval := reflect.New(dest.Type().Elem()).Elem()
+		err := store(dval, getVariantValue(src.MapIndex(key)))
+		if err != nil {
+			return err
+		}
+		dest.SetMapIndex(dkey, dval)
+	}
+	return nil
+}
+
+func storeSlice(dest, src reflect.Value) error {
+	switch {
+	case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
+		//The decoder always decodes structs as slices of interface{}
+		return storeStruct(dest, src)
+	case !kindsAreCompatible(dest.Type(), src.Type()):
+		return fmt.Errorf(
+			"dbus.Store: type mismatch: "+
+				"slice: cannot store a value of %s into %s",
+			src.Type(), dest.Type())
+	case isVariant(dest.Type()):
+		return storeSliceIntoVariant(dest, src)
+	case dest.Kind() == reflect.Interface:
+		return storeSliceIntoInterface(dest, src)
+	case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
+		return storeSliceIntoSlice(dest, src)
+	default:
+		return fmt.Errorf(
+			"dbus.Store: type mismatch: "+
+				"slice: cannot convert a value of %s into %s",
+			src.Type(), dest.Type())
+	}
+}
+
+func storeStruct(dest, src reflect.Value) error {
+	if isVariant(dest.Type()) {
+		return storeBase(dest, src)
+	}
+	dval := make([]interface{}, 0, dest.NumField())
+	dtype := dest.Type()
+	for i := 0; i < dest.NumField(); i++ {
+		field := dest.Field(i)
+		ftype := dtype.Field(i)
+		if ftype.PkgPath != "" {
+			continue
+		}
+		if ftype.Tag.Get("dbus") == "-" {
+			continue
+		}
+		dval = append(dval, field.Addr().Interface())
+	}
+	if src.Len() != len(dval) {
+		return fmt.Errorf(
+			"dbus.Store: type mismatch: "+
+				"destination struct does not have "+
+				"enough fields need: %d have: %d",
+			src.Len(), len(dval))
+	}
+	return Store(src.Interface().([]interface{}), dval...)
+}
+
+func storeSliceIntoVariant(dest, src reflect.Value) error {
+	dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
+	err := store(dv, src)
+	if err != nil {
+		return err
+	}
+	return storeBase(dest, dv)
+}
+
+func storeSliceIntoInterface(dest, src reflect.Value) error {
+	var dv reflect.Value
+	if isVariant(src.Type().Elem()) {
+		//Convert variants to interface{} recursively when converting
+		//to interface{}
+		dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
+			src.Len(), src.Cap())
+	} else {
+		dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
+	}
+	err := store(dv, src)
+	if err != nil {
+		return err
+	}
+	return storeBase(dest, dv)
+}
+
+func storeSliceIntoSlice(dest, src reflect.Value) error {
+	if dest.IsNil() || dest.Len() < src.Len() {
+		dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
+	}
+	if dest.Len() != src.Len() {
+		return fmt.Errorf(
+			"dbus.Store: type mismatch: "+
+				"slices are different lengths "+
+				"need: %d have: %d",
+			src.Len(), dest.Len())
+	}
+	for i := 0; i < src.Len(); i++ {
+		err := store(dest.Index(i), getVariantValue(src.Index(i)))
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func getVariantValue(in reflect.Value) reflect.Value {
+	if isVariant(in.Type()) {
+		return reflect.ValueOf(in.Interface().(Variant).Value())
+	}
+	return in
+}
+
+func isVariant(t reflect.Type) bool {
+	return t == variantType
+}
+
+// An ObjectPath is an object path as defined by the D-Bus spec.
+type ObjectPath string
+
+// IsValid returns whether the object path is valid.
+func (o ObjectPath) IsValid() bool {
+	s := string(o)
+	if len(s) == 0 {
+		return false
+	}
+	if s[0] != '/' {
+		return false
+	}
+	if s[len(s)-1] == '/' && len(s) != 1 {
+		return false
+	}
+	// probably not used, but technically possible
+	if s == "/" {
+		return true
+	}
+	split := strings.Split(s[1:], "/")
+	for _, v := range split {
+		if len(v) == 0 {
+			return false
+		}
+		for _, c := range v {
+			if !isMemberChar(c) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
+// documentation for more information about Unix file descriptor passsing.
+type UnixFD int32
+
+// A UnixFDIndex is the representation of a Unix file descriptor in a message.
+type UnixFDIndex uint32
+
+// alignment returns the alignment of values of type t.
+func alignment(t reflect.Type) int {
+	switch t {
+	case variantType:
+		return 1
+	case objectPathType:
+		return 4
+	case signatureType:
+		return 1
+	case interfacesType:
+		return 4
+	}
+	switch t.Kind() {
+	case reflect.Uint8:
+		return 1
+	case reflect.Uint16, reflect.Int16:
+		return 2
+	case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
+		return 4
+	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
+		return 8
+	case reflect.Ptr:
+		return alignment(t.Elem())
+	}
+	return 1
+}
+
+// isKeyType returns whether t is a valid type for a D-Bus dict.
+func isKeyType(t reflect.Type) bool {
+	switch t.Kind() {
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
+		reflect.String, reflect.Uint, reflect.Int:
+
+		return true
+	}
+	return false
+}
+
+// isValidInterface returns whether s is a valid name for an interface.
+func isValidInterface(s string) bool {
+	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
+		return false
+	}
+	elem := strings.Split(s, ".")
+	if len(elem) < 2 {
+		return false
+	}
+	for _, v := range elem {
+		if len(v) == 0 {
+			return false
+		}
+		if v[0] >= '0' && v[0] <= '9' {
+			return false
+		}
+		for _, c := range v {
+			if !isMemberChar(c) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// isValidMember returns whether s is a valid name for a member.
+func isValidMember(s string) bool {
+	if len(s) == 0 || len(s) > 255 {
+		return false
+	}
+	i := strings.Index(s, ".")
+	if i != -1 {
+		return false
+	}
+	if s[0] >= '0' && s[0] <= '9' {
+		return false
+	}
+	for _, c := range s {
+		if !isMemberChar(c) {
+			return false
+		}
+	}
+	return true
+}
+
+func isMemberChar(c rune) bool {
+	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
+		(c >= 'a' && c <= 'z') || c == '_'
+}
diff --git a/vendor/github.com/godbus/dbus/decoder.go b/vendor/github.com/godbus/dbus/decoder.go
new file mode 100644
index 000000000..ef50dcab9
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/decoder.go
@@ -0,0 +1,228 @@
+package dbus
+
+import (
+	"encoding/binary"
+	"io"
+	"reflect"
+)
+
+type decoder struct {
+	in    io.Reader
+	order binary.ByteOrder
+	pos   int
+}
+
+// newDecoder returns a new decoder that reads values from in. The input is
+// expected to be in the given byte order.
+func newDecoder(in io.Reader, order binary.ByteOrder) *decoder {
+	dec := new(decoder)
+	dec.in = in
+	dec.order = order
+	return dec
+}
+
+// align aligns the input to the given boundary and panics on error.
+func (dec *decoder) align(n int) {
+	if dec.pos%n != 0 {
+		newpos := (dec.pos + n - 1) & ^(n - 1)
+		empty := make([]byte, newpos-dec.pos)
+		if _, err := io.ReadFull(dec.in, empty); err != nil {
+			panic(err)
+		}
+		dec.pos = newpos
+	}
+}
+
+// Calls binary.Read(dec.in, dec.order, v) and panics on read errors.
+func (dec *decoder) binread(v interface{}) {
+	if err := binary.Read(dec.in, dec.order, v); err != nil {
+		panic(err)
+	}
+}
+
+func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
+	defer func() {
+		var ok bool
+		v := recover()
+		if err, ok = v.(error); ok {
+			if err == io.EOF || err == io.ErrUnexpectedEOF {
+				err = FormatError("unexpected EOF")
+			}
+		}
+	}()
+	vs = make([]interface{}, 0)
+	s := sig.str
+	for s != "" {
+		err, rem := validSingle(s, 0)
+		if err != nil {
+			return nil, err
+		}
+		v := dec.decode(s[:len(s)-len(rem)], 0)
+		vs = append(vs, v)
+		s = rem
+	}
+	return vs, nil
+}
+
+func (dec *decoder) decode(s string, depth int) interface{} {
+	dec.align(alignment(typeFor(s)))
+	switch s[0] {
+	case 'y':
+		var b [1]byte
+		if _, err := dec.in.Read(b[:]); err != nil {
+			panic(err)
+		}
+		dec.pos++
+		return b[0]
+	case 'b':
+		i := dec.decode("u", depth).(uint32)
+		switch {
+		case i == 0:
+			return false
+		case i == 1:
+			return true
+		default:
+			panic(FormatError("invalid value for boolean"))
+		}
+	case 'n':
+		var i int16
+		dec.binread(&i)
+		dec.pos += 2
+		return i
+	case 'i':
+		var i int32
+		dec.binread(&i)
+		dec.pos += 4
+		return i
+	case 'x':
+		var i int64
+		dec.binread(&i)
+		dec.pos += 8
+		return i
+	case 'q':
+		var i uint16
+		dec.binread(&i)
+		dec.pos += 2
+		return i
+	case 'u':
+		var i uint32
+		dec.binread(&i)
+		dec.pos += 4
+		return i
+	case 't':
+		var i uint64
+		dec.binread(&i)
+		dec.pos += 8
+		return i
+	case 'd':
+		var f float64
+		dec.binread(&f)
+		dec.pos += 8
+		return f
+	case 's':
+		length := dec.decode("u", depth).(uint32)
+		b := make([]byte, int(length)+1)
+		if _, err := io.ReadFull(dec.in, b); err != nil {
+			panic(err)
+		}
+		dec.pos += int(length) + 1
+		return string(b[:len(b)-1])
+	case 'o':
+		return ObjectPath(dec.decode("s", depth).(string))
+	case 'g':
+		length := dec.decode("y", depth).(byte)
+		b := make([]byte, int(length)+1)
+		if _, err := io.ReadFull(dec.in, b); err != nil {
+			panic(err)
+		}
+		dec.pos += int(length) + 1
+		sig, err := ParseSignature(string(b[:len(b)-1]))
+		if err != nil {
+			panic(err)
+		}
+		return sig
+	case 'v':
+		if depth >= 64 {
+			panic(FormatError("input exceeds container depth limit"))
+		}
+		var variant Variant
+		sig := dec.decode("g", depth).(Signature)
+		if len(sig.str) == 0 {
+			panic(FormatError("variant signature is empty"))
+		}
+		err, rem := validSingle(sig.str, 0)
+		if err != nil {
+			panic(err)
+		}
+		if rem != "" {
+			panic(FormatError("variant signature has multiple types"))
+		}
+		variant.sig = sig
+		variant.value = dec.decode(sig.str, depth+1)
+		return variant
+	case 'h':
+		return UnixFDIndex(dec.decode("u", depth).(uint32))
+	case 'a':
+		if len(s) > 1 && s[1] == '{' {
+			ksig := s[2:3]
+			vsig := s[3 : len(s)-1]
+			v := reflect.MakeMap(reflect.MapOf(typeFor(ksig), typeFor(vsig)))
+			if depth >= 63 {
+				panic(FormatError("input exceeds container depth limit"))
+			}
+			length := dec.decode("u", depth).(uint32)
+			// Even for empty maps, the correct padding must be included
+			dec.align(8)
+			spos := dec.pos
+			for dec.pos < spos+int(length) {
+				dec.align(8)
+				if !isKeyType(v.Type().Key()) {
+					panic(InvalidTypeError{v.Type()})
+				}
+				kv := dec.decode(ksig, depth+2)
+				vv := dec.decode(vsig, depth+2)
+				v.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv))
+			}
+			return v.Interface()
+		}
+		if depth >= 64 {
+			panic(FormatError("input exceeds container depth limit"))
+		}
+		length := dec.decode("u", depth).(uint32)
+		v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
+		// Even for empty arrays, the correct padding must be included
+		dec.align(alignment(typeFor(s[1:])))
+		spos := dec.pos
+		for dec.pos < spos+int(length) {
+			ev := dec.decode(s[1:], depth+1)
+			v = reflect.Append(v, reflect.ValueOf(ev))
+		}
+		return v.Interface()
+	case '(':
+		if depth >= 64 {
+			panic(FormatError("input exceeds container depth limit"))
+		}
+		dec.align(8)
+		v := make([]interface{}, 0)
+		s = s[1 : len(s)-1]
+		for s != "" {
+			err, rem := validSingle(s, 0)
+			if err != nil {
+				panic(err)
+			}
+			ev := dec.decode(s[:len(s)-len(rem)], depth+1)
+			v = append(v, ev)
+			s = rem
+		}
+		return v
+	default:
+		panic(SignatureError{Sig: s})
+	}
+}
+
+// A FormatError is an error in the wire format.
+type FormatError string
+
+func (e FormatError) Error() string {
+	return "dbus: wire format error: " + string(e)
+}
diff --git a/vendor/github.com/godbus/dbus/default_handler.go b/vendor/github.com/godbus/dbus/default_handler.go
new file mode 100644
index 000000000..e81f73ac5
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/default_handler.go
@@ -0,0 +1,291 @@
+package dbus
+
+import (
+	"bytes"
+	"reflect"
+	"strings"
+	"sync"
+)
+
+func newIntrospectIntf(h *defaultHandler) *exportedIntf {
+	methods := make(map[string]Method)
+	methods["Introspect"] = exportedMethod{
+		reflect.ValueOf(func(msg Message) (string, *Error) {
+			path := msg.Headers[FieldPath].value.(ObjectPath)
+			return h.introspectPath(path), nil
+		}),
+	}
+	return newExportedIntf(methods, true)
+}
+
+//NewDefaultHandler returns an instance of the default
+//call handler. This is useful if you want to implement only
+//one of the two handlers but not both.
+func NewDefaultHandler() *defaultHandler {
+	h := &defaultHandler{
+		objects:     make(map[ObjectPath]*exportedObj),
+		defaultIntf: make(map[string]*exportedIntf),
+	}
+	h.defaultIntf["org.freedesktop.DBus.Introspectable"] = newIntrospectIntf(h)
+	return h
+}
+
+type defaultHandler struct {
+	sync.RWMutex
+	objects     map[ObjectPath]*exportedObj
+	defaultIntf map[string]*exportedIntf
+}
+
+func (h *defaultHandler) PathExists(path ObjectPath) bool {
+	_, ok := h.objects[path]
+	return ok
+}
+
+func (h *defaultHandler) introspectPath(path ObjectPath) string {
+	subpath := make(map[string]struct{})
+	var xml bytes.Buffer
+	xml.WriteString("<node>")
+	for obj, _ := range h.objects {
+		p := string(path)
+		if p != "/" {
+			p += "/"
+		}
+		if strings.HasPrefix(string(obj), p) {
+			node_name := strings.Split(string(obj[len(p):]), "/")[0]
+			subpath[node_name] = struct{}{}
+		}
+	}
+	for s, _ := range subpath {
+		xml.WriteString("\n\t<node name=\"" + s + "\"/>")
+	}
+	xml.WriteString("\n</node>")
+	return xml.String()
+}
+
+func (h *defaultHandler) LookupObject(path ObjectPath) (ServerObject, bool) {
+	h.RLock()
+	defer h.RUnlock()
+	object, ok := h.objects[path]
+	if ok {
+		return object, ok
+	}
+
+	// If an object wasn't found for this exact path,
+	// look for a matching subtree registration
+	subtreeObject := newExportedObject()
+	path = path[:strings.LastIndex(string(path), "/")]
+	for len(path) > 0 {
+		object, ok = h.objects[path]
+		if ok {
+			for name, iface := range object.interfaces {
+				// Only include this handler if it registered for the subtree
+				if iface.isFallbackInterface() {
+					subtreeObject.interfaces[name] = iface
+				}
+			}
+			break
+		}
+
+		path = path[:strings.LastIndex(string(path), "/")]
+	}
+
+	for name, intf := range h.defaultIntf {
+		if _, exists := subtreeObject.interfaces[name]; exists {
+			continue
+		}
+		subtreeObject.interfaces[name] = intf
+	}
+
+	return subtreeObject, true
+}
+
+func (h *defaultHandler) AddObject(path ObjectPath, object *exportedObj) {
+	h.Lock()
+	h.objects[path] = object
+	h.Unlock()
+}
+
+func (h *defaultHandler) DeleteObject(path ObjectPath) {
+	h.Lock()
+	delete(h.objects, path)
+	h.Unlock()
+}
+
+type exportedMethod struct {
+	reflect.Value
+}
+
+func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) {
+	t := m.Type()
+
+	params := make([]reflect.Value, len(args))
+	for i := 0; i < len(args); i++ {
+		params[i] = reflect.ValueOf(args[i]).Elem()
+	}
+
+	ret := m.Value.Call(params)
+
+	err := ret[t.NumOut()-1].Interface().(*Error)
+	ret = ret[:t.NumOut()-1]
+	out := make([]interface{}, len(ret))
+	for i, val := range ret {
+		out[i] = val.Interface()
+	}
+	if err == nil {
+		//concrete type to interface nil is a special case
+		return out, nil
+	}
+	return out, err
+}
+
+func (m exportedMethod) NumArguments() int {
+	return m.Value.Type().NumIn()
+}
+
+func (m exportedMethod) ArgumentValue(i int) interface{} {
+	return reflect.Zero(m.Type().In(i)).Interface()
+}
+
+func (m exportedMethod) NumReturns() int {
+	return m.Value.Type().NumOut()
+}
+
+func (m exportedMethod) ReturnValue(i int) interface{} {
+	return reflect.Zero(m.Type().Out(i)).Interface()
+}
+
+func newExportedObject() *exportedObj {
+	return &exportedObj{
+		interfaces: make(map[string]*exportedIntf),
+	}
+}
+
+type exportedObj struct {
+	interfaces map[string]*exportedIntf
+}
+
+func (obj *exportedObj) LookupInterface(name string) (Interface, bool) {
+	if name == "" {
+		return obj, true
+	}
+	intf, exists := obj.interfaces[name]
+	return intf, exists
+}
+
+func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) {
+	obj.interfaces[name] = iface
+}
+
+func (obj *exportedObj) DeleteInterface(name string) {
+	delete(obj.interfaces, name)
+}
+
+func (obj *exportedObj) LookupMethod(name string) (Method, bool) {
+	for _, intf := range obj.interfaces {
+		method, exists := intf.LookupMethod(name)
+		if exists {
+			return method, exists
+		}
+	}
+	return nil, false
+}
+
+func (obj *exportedObj) isFallbackInterface() bool {
+	return false
+}
+
+func newExportedIntf(methods map[string]Method, includeSubtree bool) *exportedIntf {
+	return &exportedIntf{
+		methods:        methods,
+		includeSubtree: includeSubtree,
+	}
+}
+
+type exportedIntf struct {
+	methods map[string]Method
+
+	// Whether or not this export is for the entire subtree
+	includeSubtree bool
+}
+
+func (obj *exportedIntf) LookupMethod(name string) (Method, bool) {
+	out, exists := obj.methods[name]
+	return out, exists
+}
+
+func (obj *exportedIntf) isFallbackInterface() bool {
+	return obj.includeSubtree
+}
+
+//NewDefaultSignalHandler returns an instance of the default
+//signal handler. This is useful if you want to implement only
+//one of the two handlers but not both.
+func NewDefaultSignalHandler() *defaultSignalHandler {
+	return &defaultSignalHandler{}
+}
+
+func isDefaultSignalHandler(handler SignalHandler) bool {
+	_, ok := handler.(*defaultSignalHandler)
+	return ok
+}
+
+type defaultSignalHandler struct {
+	sync.RWMutex
+	closed  bool
+	signals []chan<- *Signal
+}
+
+func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
+	go func() {
+		sh.RLock()
+		defer sh.RUnlock()
+		if sh.closed {
+			return
+		}
+		for _, ch := range sh.signals {
+			ch <- signal
+		}
+	}()
+}
+
+func (sh *defaultSignalHandler) Init() error {
+	sh.Lock()
+	sh.signals = make([]chan<- *Signal, 0)
+	sh.Unlock()
+	return nil
+}
+
+func (sh *defaultSignalHandler) Terminate() {
+	sh.Lock()
+	sh.closed = true
+	for _, ch := range sh.signals {
+		close(ch)
+	}
+	sh.signals = nil
+	sh.Unlock()
+}
+
+func (sh *defaultSignalHandler) addSignal(ch chan<- *Signal) {
+	sh.Lock()
+	defer sh.Unlock()
+	if sh.closed {
+		return
+	}
+	sh.signals = append(sh.signals, ch)
+
+}
+
+func (sh *defaultSignalHandler) removeSignal(ch chan<- *Signal) {
+	sh.Lock()
+	defer sh.Unlock()
+	if sh.closed {
+		return
+	}
+	for i := len(sh.signals) - 1; i >= 0; i-- {
+		if ch == sh.signals[i] {
+			copy(sh.signals[i:], sh.signals[i+1:])
+			sh.signals[len(sh.signals)-1] = nil
+			sh.signals = sh.signals[:len(sh.signals)-1]
+		}
+	}
+}
diff --git a/vendor/github.com/godbus/dbus/doc.go b/vendor/github.com/godbus/dbus/doc.go
new file mode 100644
index 000000000..895036a8c
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/doc.go
@@ -0,0 +1,69 @@
+/*
+Package dbus implements bindings to the D-Bus message bus system.
+
+To use the message bus API, you first need to connect to a bus (usually the
+session or system bus). The acquired connection then can be used to call methods
+on remote objects and emit or receive signals. Using the Export method, you can
+arrange D-Bus methods calls to be directly translated to method calls on a Go
+value.
+
+Conversion Rules
+
+For outgoing messages, Go types are automatically converted to the
+corresponding D-Bus types. The following types are directly encoded as their
+respective D-Bus equivalents:
+
+     Go type     | D-Bus type
+     ------------+-----------
+     byte        | BYTE
+     bool        | BOOLEAN
+     int16       | INT16
+     uint16      | UINT16
+     int         | INT32
+     uint        | UINT32
+     int32       | INT32
+     uint32      | UINT32
+     int64       | INT64
+     uint64      | UINT64
+     float64     | DOUBLE
+     string      | STRING
+     ObjectPath  | OBJECT_PATH
+     Signature   | SIGNATURE
+     Variant     | VARIANT
+     interface{} | VARIANT
+     UnixFDIndex | UNIX_FD
+
+Slices and arrays encode as ARRAYs of their element type.
+
+Maps encode as DICTs, provided that their key type can be used as a key for
+a DICT.
+
+Structs other than Variant and Signature encode as a STRUCT containing their
+exported fields. Fields whose tags contain `dbus:"-"` and unexported fields will
+be skipped.
+
+Pointers encode as the value they're pointed to.
+
+Types convertible to one of the base types above will be mapped as the
+base type.
+
+Trying to encode any other type or a slice, map or struct containing an
+unsupported type will result in an InvalidTypeError.
+
+For incoming messages, the inverse of these rules are used, with the exception
+of STRUCTs. Incoming STRUCTS are represented as a slice of empty interfaces
+containing the struct fields in the correct order. The Store function can be
+used to convert such values to Go structs.
+
+Unix FD passing
+
+Handling Unix file descriptors deserves special mention. To use them, you should
+first check that they are supported on a connection by calling SupportsUnixFDs.
+If it returns true, all method of Connection will translate messages containing
+UnixFD's to messages that are accompanied by the given file descriptors with the
+UnixFD values being substituted by the correct indices. Similarily, the indices
+of incoming messages are automatically resolved. It shouldn't be necessary to use
+UnixFDIndex.
+
+*/
+package dbus
diff --git a/vendor/github.com/godbus/dbus/encoder.go b/vendor/github.com/godbus/dbus/encoder.go
new file mode 100644
index 000000000..8bb717761
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/encoder.go
@@ -0,0 +1,210 @@
+package dbus
+
+import (
+	"bytes"
+	"encoding/binary"
+	"io"
+	"reflect"
+)
+
+// An encoder encodes values to the D-Bus wire format.
+type encoder struct {
+	out   io.Writer
+	order binary.ByteOrder
+	pos   int
+}
+
+// NewEncoder returns a new encoder that writes to out in the given byte order.
+func newEncoder(out io.Writer, order binary.ByteOrder) *encoder {
+	return newEncoderAtOffset(out, 0, order)
+}
+
+// newEncoderAtOffset returns a new encoder that writes to out in the given
+// byte order. Specify the offset to initialize pos for proper alignment
+// computation.
+func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder {
+	enc := new(encoder)
+	enc.out = out
+	enc.order = order
+	enc.pos = offset
+	return enc
+}
+
+// Aligns the next output to be on a multiple of n. Panics on write errors.
+func (enc *encoder) align(n int) {
+	pad := enc.padding(0, n)
+	if pad > 0 {
+		empty := make([]byte, pad)
+		if _, err := enc.out.Write(empty); err != nil {
+			panic(err)
+		}
+		enc.pos += pad
+	}
+}
+
+// pad returns the number of bytes of padding, based on current position and additional offset.
+// and alignment.
+func (enc *encoder) padding(offset, algn int) int {
+	abs := enc.pos + offset
+	if abs%algn != 0 {
+		newabs := (abs + algn - 1) & ^(algn - 1)
+		return newabs - abs
+	}
+	return 0
+}
+
+// Calls binary.Write(enc.out, enc.order, v) and panics on write errors.
+func (enc *encoder) binwrite(v interface{}) {
+	if err := binary.Write(enc.out, enc.order, v); err != nil {
+		panic(err)
+	}
+}
+
+// Encode encodes the given values to the underyling reader. All written values
+// are aligned properly as required by the D-Bus spec.
+func (enc *encoder) Encode(vs ...interface{}) (err error) {
+	defer func() {
+		err, _ = recover().(error)
+	}()
+	for _, v := range vs {
+		enc.encode(reflect.ValueOf(v), 0)
+	}
+	return nil
+}
+
+// encode encodes the given value to the writer and panics on error. depth holds
+// the depth of the container nesting.
+func (enc *encoder) encode(v reflect.Value, depth int) {
+	enc.align(alignment(v.Type()))
+	switch v.Kind() {
+	case reflect.Uint8:
+		var b [1]byte
+		b[0] = byte(v.Uint())
+		if _, err := enc.out.Write(b[:]); err != nil {
+			panic(err)
+		}
+		enc.pos++
+	case reflect.Bool:
+		if v.Bool() {
+			enc.encode(reflect.ValueOf(uint32(1)), depth)
+		} else {
+			enc.encode(reflect.ValueOf(uint32(0)), depth)
+		}
+	case reflect.Int16:
+		enc.binwrite(int16(v.Int()))
+		enc.pos += 2
+	case reflect.Uint16:
+		enc.binwrite(uint16(v.Uint()))
+		enc.pos += 2
+	case reflect.Int, reflect.Int32:
+		enc.binwrite(int32(v.Int()))
+		enc.pos += 4
+	case reflect.Uint, reflect.Uint32:
+		enc.binwrite(uint32(v.Uint()))
+		enc.pos += 4
+	case reflect.Int64:
+		enc.binwrite(v.Int())
+		enc.pos += 8
+	case reflect.Uint64:
+		enc.binwrite(v.Uint())
+		enc.pos += 8
+	case reflect.Float64:
+		enc.binwrite(v.Float())
+		enc.pos += 8
+	case reflect.String:
+		enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth)
+		b := make([]byte, v.Len()+1)
+		copy(b, v.String())
+		b[len(b)-1] = 0
+		n, err := enc.out.Write(b)
+		if err != nil {
+			panic(err)
+		}
+		enc.pos += n
+	case reflect.Ptr:
+		enc.encode(v.Elem(), depth)
+	case reflect.Slice, reflect.Array:
+		if depth >= 64 {
+			panic(FormatError("input exceeds container depth limit"))
+		}
+		// Lookahead offset: 4 bytes for uint32 length (with alignment),
+		// plus alignment for elements.
+		n := enc.padding(0, 4) + 4
+		offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem()))
+
+		var buf bytes.Buffer
+		bufenc := newEncoderAtOffset(&buf, offset, enc.order)
+
+		for i := 0; i < v.Len(); i++ {
+			bufenc.encode(v.Index(i), depth+1)
+		}
+		enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
+		length := buf.Len()
+		enc.align(alignment(v.Type().Elem()))
+		if _, err := buf.WriteTo(enc.out); err != nil {
+			panic(err)
+		}
+		enc.pos += length
+	case reflect.Struct:
+		if depth >= 64 && v.Type() != signatureType {
+			panic(FormatError("input exceeds container depth limit"))
+		}
+		switch t := v.Type(); t {
+		case signatureType:
+			str := v.Field(0)
+			enc.encode(reflect.ValueOf(byte(str.Len())), depth+1)
+			b := make([]byte, str.Len()+1)
+			copy(b, str.String())
+			b[len(b)-1] = 0
+			n, err := enc.out.Write(b)
+			if err != nil {
+				panic(err)
+			}
+			enc.pos += n
+		case variantType:
+			variant := v.Interface().(Variant)
+			enc.encode(reflect.ValueOf(variant.sig), depth+1)
+			enc.encode(reflect.ValueOf(variant.value), depth+1)
+		default:
+			for i := 0; i < v.Type().NumField(); i++ {
+				field := t.Field(i)
+				if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
+					enc.encode(v.Field(i), depth+1)
+				}
+			}
+		}
+	case reflect.Map:
+		// Maps are arrays of structures, so they actually increase the depth by
+		// 2.
+		if depth >= 63 {
+			panic(FormatError("input exceeds container depth limit"))
+		}
+		if !isKeyType(v.Type().Key()) {
+			panic(InvalidTypeError{v.Type()})
+		}
+		keys := v.MapKeys()
+		// Lookahead offset: 4 bytes for uint32 length (with alignment),
+		// plus 8-byte alignment
+		n := enc.padding(0, 4) + 4
+		offset := enc.pos + n + enc.padding(n, 8)
+
+		var buf bytes.Buffer
+		bufenc := newEncoderAtOffset(&buf, offset, enc.order)
+		for _, k := range keys {
+			bufenc.align(8)
+			bufenc.encode(k, depth+2)
+			bufenc.encode(v.MapIndex(k), depth+2)
+		}
+		enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
+		length := buf.Len()
+		enc.align(8)
+		if _, err := buf.WriteTo(enc.out); err != nil {
+			panic(err)
+		}
+		enc.pos += length
+	case reflect.Interface:
+		enc.encode(reflect.ValueOf(MakeVariant(v.Interface())), depth)
+	default:
+		panic(InvalidTypeError{v.Type()})
+	}
+}
diff --git a/vendor/github.com/godbus/dbus/export.go b/vendor/github.com/godbus/dbus/export.go
new file mode 100644
index 000000000..95d0e2958
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/export.go
@@ -0,0 +1,412 @@
+package dbus
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+)
+
+var (
+	ErrMsgInvalidArg = Error{
+		"org.freedesktop.DBus.Error.InvalidArgs",
+		[]interface{}{"Invalid type / number of args"},
+	}
+	ErrMsgNoObject = Error{
+		"org.freedesktop.DBus.Error.NoSuchObject",
+		[]interface{}{"No such object"},
+	}
+	ErrMsgUnknownMethod = Error{
+		"org.freedesktop.DBus.Error.UnknownMethod",
+		[]interface{}{"Unknown / invalid method"},
+	}
+	ErrMsgUnknownInterface = Error{
+		"org.freedesktop.DBus.Error.UnknownInterface",
+		[]interface{}{"Object does not implement the interface"},
+	}
+)
+
+func MakeFailedError(err error) *Error {
+	return &Error{
+		"org.freedesktop.DBus.Error.Failed",
+		[]interface{}{err.Error()},
+	}
+}
+
+// Sender is a type which can be used in exported methods to receive the message
+// sender.
+type Sender string
+
+func computeMethodName(name string, mapping map[string]string) string {
+	newname, ok := mapping[name]
+	if ok {
+		name = newname
+	}
+	return name
+}
+
+func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
+	if in == nil {
+		return nil
+	}
+	methods := make(map[string]reflect.Value)
+	val := reflect.ValueOf(in)
+	typ := val.Type()
+	for i := 0; i < typ.NumMethod(); i++ {
+		methtype := typ.Method(i)
+		method := val.Method(i)
+		t := method.Type()
+		// only track valid methods must return *Error as last arg
+		// and must be exported
+		if t.NumOut() == 0 ||
+			t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) ||
+			methtype.PkgPath != "" {
+			continue
+		}
+		// map names while building table
+		methods[computeMethodName(methtype.Name, mapping)] = method
+	}
+	return methods
+}
+
+func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) {
+	pointers := make([]interface{}, m.NumArguments())
+	decode := make([]interface{}, 0, len(body))
+
+	for i := 0; i < m.NumArguments(); i++ {
+		tp := reflect.TypeOf(m.ArgumentValue(i))
+		val := reflect.New(tp)
+		pointers[i] = val.Interface()
+		if tp == reflect.TypeOf((*Sender)(nil)).Elem() {
+			val.Elem().SetString(sender)
+		} else if tp == reflect.TypeOf((*Message)(nil)).Elem() {
+			val.Elem().Set(reflect.ValueOf(*msg))
+		} else {
+			decode = append(decode, pointers[i])
+		}
+	}
+
+	if len(decode) != len(body) {
+		return nil, ErrMsgInvalidArg
+	}
+
+	if err := Store(body, decode...); err != nil {
+		return nil, ErrMsgInvalidArg
+	}
+
+	return pointers, nil
+}
+
+func (conn *Conn) decodeArguments(m Method, sender string, msg *Message) ([]interface{}, error) {
+	if decoder, ok := m.(ArgumentDecoder); ok {
+		return decoder.DecodeArguments(conn, sender, msg, msg.Body)
+	}
+	return standardMethodArgumentDecode(m, sender, msg, msg.Body)
+}
+
+// handleCall handles the given method call (i.e. looks if it's one of the
+// pre-implemented ones and searches for a corresponding handler if not).
+func (conn *Conn) handleCall(msg *Message) {
+	name := msg.Headers[FieldMember].value.(string)
+	path := msg.Headers[FieldPath].value.(ObjectPath)
+	ifaceName, _ := msg.Headers[FieldInterface].value.(string)
+	sender, hasSender := msg.Headers[FieldSender].value.(string)
+	serial := msg.serial
+	if ifaceName == "org.freedesktop.DBus.Peer" {
+		switch name {
+		case "Ping":
+			conn.sendReply(sender, serial)
+		case "GetMachineId":
+			conn.sendReply(sender, serial, conn.uuid)
+		default:
+			conn.sendError(ErrMsgUnknownMethod, sender, serial)
+		}
+		return
+	}
+	if len(name) == 0 {
+		conn.sendError(ErrMsgUnknownMethod, sender, serial)
+	}
+
+	object, ok := conn.handler.LookupObject(path)
+	if !ok {
+		conn.sendError(ErrMsgNoObject, sender, serial)
+		return
+	}
+
+	iface, exists := object.LookupInterface(ifaceName)
+	if !exists {
+		conn.sendError(ErrMsgUnknownInterface, sender, serial)
+		return
+	}
+
+	m, exists := iface.LookupMethod(name)
+	if !exists {
+		conn.sendError(ErrMsgUnknownMethod, sender, serial)
+		return
+	}
+	args, err := conn.decodeArguments(m, sender, msg)
+	if err != nil {
+		conn.sendError(err, sender, serial)
+		return
+	}
+
+	ret, err := m.Call(args...)
+	if err != nil {
+		conn.sendError(err, sender, serial)
+		return
+	}
+
+	if msg.Flags&FlagNoReplyExpected == 0 {
+		reply := new(Message)
+		reply.Type = TypeMethodReply
+		reply.serial = conn.getSerial()
+		reply.Headers = make(map[HeaderField]Variant)
+		if hasSender {
+			reply.Headers[FieldDestination] = msg.Headers[FieldSender]
+		}
+		reply.Headers[FieldReplySerial] = MakeVariant(msg.serial)
+		reply.Body = make([]interface{}, len(ret))
+		for i := 0; i < len(ret); i++ {
+			reply.Body[i] = ret[i]
+		}
+		reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
+
+		conn.sendMessage(reply)
+	}
+}
+
+// Emit emits the given signal on the message bus. The name parameter must be
+// formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost".
+func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error {
+	if !path.IsValid() {
+		return errors.New("dbus: invalid object path")
+	}
+	i := strings.LastIndex(name, ".")
+	if i == -1 {
+		return errors.New("dbus: invalid method name")
+	}
+	iface := name[:i]
+	member := name[i+1:]
+	if !isValidMember(member) {
+		return errors.New("dbus: invalid method name")
+	}
+	if !isValidInterface(iface) {
+		return errors.New("dbus: invalid interface name")
+	}
+	msg := new(Message)
+	msg.Type = TypeSignal
+	msg.serial = conn.getSerial()
+	msg.Headers = make(map[HeaderField]Variant)
+	msg.Headers[FieldInterface] = MakeVariant(iface)
+	msg.Headers[FieldMember] = MakeVariant(member)
+	msg.Headers[FieldPath] = MakeVariant(path)
+	msg.Body = values
+	if len(values) > 0 {
+		msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
+	}
+
+	var closed bool
+	conn.sendMessageAndIfClosed(msg, func() {
+		closed = true
+	})
+	if closed {
+		return ErrClosed
+	}
+	return nil
+}
+
+// Export registers the given value to be exported as an object on the
+// message bus.
+//
+// If a method call on the given path and interface is received, an exported
+// method with the same name is called with v as the receiver if the
+// parameters match and the last return value is of type *Error. If this
+// *Error is not nil, it is sent back to the caller as an error.
+// Otherwise, a method reply is sent with the other return values as its body.
+//
+// Any parameters with the special type Sender are set to the sender of the
+// dbus message when the method is called. Parameters of this type do not
+// contribute to the dbus signature of the method (i.e. the method is exposed
+// as if the parameters of type Sender were not there).
+//
+// Similarly, any parameters with the type Message are set to the raw message
+// received on the bus. Again, parameters of this type do not contribute to the
+// dbus signature of the method.
+//
+// Every method call is executed in a new goroutine, so the method may be called
+// in multiple goroutines at once.
+//
+// Method calls on the interface org.freedesktop.DBus.Peer will be automatically
+// handled for every object.
+//
+// Passing nil as the first parameter will cause conn to cease handling calls on
+// the given combination of path and interface.
+//
+// Export returns an error if path is not a valid path name.
+func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
+	return conn.ExportWithMap(v, nil, path, iface)
+}
+
+// ExportWithMap works exactly like Export but provides the ability to remap
+// method names (e.g. export a lower-case method).
+//
+// The keys in the map are the real method names (exported on the struct), and
+// the values are the method names to be exported on DBus.
+func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
+	return conn.export(getMethods(v, mapping), path, iface, false)
+}
+
+// ExportSubtree works exactly like Export but registers the given value for
+// an entire subtree rather under the root path provided.
+//
+// In order to make this useful, one parameter in each of the value's exported
+// methods should be a Message, in which case it will contain the raw message
+// (allowing one to get access to the path that caused the method to be called).
+//
+// Note that more specific export paths take precedence over less specific. For
+// example, a method call using the ObjectPath /foo/bar/baz will call a method
+// exported on /foo/bar before a method exported on /foo.
+func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error {
+	return conn.ExportSubtreeWithMap(v, nil, path, iface)
+}
+
+// ExportSubtreeWithMap works exactly like ExportSubtree but provides the
+// ability to remap method names (e.g. export a lower-case method).
+//
+// The keys in the map are the real method names (exported on the struct), and
+// the values are the method names to be exported on DBus.
+func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
+	return conn.export(getMethods(v, mapping), path, iface, true)
+}
+
+// ExportMethodTable like Export registers the given methods as an object
+// on the message bus. Unlike Export the it uses a method table to define
+// the object instead of a native go object.
+//
+// The method table is a map from method name to function closure
+// representing the method. This allows an object exported on the bus to not
+// necessarily be a native go object. It can be useful for generating exposed
+// methods on the fly.
+//
+// Any non-function objects in the method table are ignored.
+func (conn *Conn) ExportMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
+	return conn.exportMethodTable(methods, path, iface, false)
+}
+
+// Like ExportSubtree, but with the same caveats as ExportMethodTable.
+func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
+	return conn.exportMethodTable(methods, path, iface, true)
+}
+
+func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error {
+	out := make(map[string]reflect.Value)
+	for name, method := range methods {
+		rval := reflect.ValueOf(method)
+		if rval.Kind() != reflect.Func {
+			continue
+		}
+		t := rval.Type()
+		// only track valid methods must return *Error as last arg
+		if t.NumOut() == 0 ||
+			t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) {
+			continue
+		}
+		out[name] = rval
+	}
+	return conn.export(out, path, iface, includeSubtree)
+}
+
+func (conn *Conn) unexport(h *defaultHandler, path ObjectPath, iface string) error {
+	if h.PathExists(path) {
+		obj := h.objects[path]
+		obj.DeleteInterface(iface)
+		if len(obj.interfaces) == 0 {
+			h.DeleteObject(path)
+		}
+	}
+	return nil
+}
+
+// exportWithMap is the worker function for all exports/registrations.
+func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error {
+	h, ok := conn.handler.(*defaultHandler)
+	if !ok {
+		return fmt.Errorf(
+			`dbus: export only allowed on the default hander handler have %T"`,
+			conn.handler)
+	}
+
+	if !path.IsValid() {
+		return fmt.Errorf(`dbus: Invalid path name: "%s"`, path)
+	}
+
+	// Remove a previous export if the interface is nil
+	if methods == nil {
+		return conn.unexport(h, path, iface)
+	}
+
+	// If this is the first handler for this path, make a new map to hold all
+	// handlers for this path.
+	if !h.PathExists(path) {
+		h.AddObject(path, newExportedObject())
+	}
+
+	exportedMethods := make(map[string]Method)
+	for name, method := range methods {
+		exportedMethods[name] = exportedMethod{method}
+	}
+
+	// Finally, save this handler
+	obj := h.objects[path]
+	obj.AddInterface(iface, newExportedIntf(exportedMethods, includeSubtree))
+
+	return nil
+}
+
+// ReleaseName calls org.freedesktop.DBus.ReleaseName and awaits a response.
+func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) {
+	var r uint32
+	err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r)
+	if err != nil {
+		return 0, err
+	}
+	return ReleaseNameReply(r), nil
+}
+
+// RequestName calls org.freedesktop.DBus.RequestName and awaits a response.
+func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) {
+	var r uint32
+	err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r)
+	if err != nil {
+		return 0, err
+	}
+	return RequestNameReply(r), nil
+}
+
+// ReleaseNameReply is the reply to a ReleaseName call.
+type ReleaseNameReply uint32
+
+const (
+	ReleaseNameReplyReleased ReleaseNameReply = 1 + iota
+	ReleaseNameReplyNonExistent
+	ReleaseNameReplyNotOwner
+)
+
+// RequestNameFlags represents the possible flags for a RequestName call.
+type RequestNameFlags uint32
+
+const (
+	NameFlagAllowReplacement RequestNameFlags = 1 << iota
+	NameFlagReplaceExisting
+	NameFlagDoNotQueue
+)
+
+// RequestNameReply is the reply to a RequestName call.
+type RequestNameReply uint32
+
+const (
+	RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota
+	RequestNameReplyInQueue
+	RequestNameReplyExists
+	RequestNameReplyAlreadyOwner
+)
diff --git a/vendor/github.com/godbus/dbus/homedir.go b/vendor/github.com/godbus/dbus/homedir.go
new file mode 100644
index 000000000..0b745f931
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/homedir.go
@@ -0,0 +1,28 @@
+package dbus
+
+import (
+	"os"
+	"sync"
+)
+
+var (
+	homeDir     string
+	homeDirLock sync.Mutex
+)
+
+func getHomeDir() string {
+	homeDirLock.Lock()
+	defer homeDirLock.Unlock()
+
+	if homeDir != "" {
+		return homeDir
+	}
+
+	homeDir = os.Getenv("HOME")
+	if homeDir != "" {
+		return homeDir
+	}
+
+	homeDir = lookupHomeDir()
+	return homeDir
+}
diff --git a/vendor/github.com/godbus/dbus/homedir_dynamic.go b/vendor/github.com/godbus/dbus/homedir_dynamic.go
new file mode 100644
index 000000000..2732081e7
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/homedir_dynamic.go
@@ -0,0 +1,15 @@
+// +build !static_build
+
+package dbus
+
+import (
+	"os/user"
+)
+
+func lookupHomeDir() string {
+	u, err := user.Current()
+	if err != nil {
+		return "/"
+	}
+	return u.HomeDir
+}
diff --git a/vendor/github.com/godbus/dbus/homedir_static.go b/vendor/github.com/godbus/dbus/homedir_static.go
new file mode 100644
index 000000000..b9d9cb552
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/homedir_static.go
@@ -0,0 +1,45 @@
+// +build static_build
+
+package dbus
+
+import (
+	"bufio"
+	"os"
+	"strconv"
+	"strings"
+)
+
+func lookupHomeDir() string {
+	myUid := os.Getuid()
+
+	f, err := os.Open("/etc/passwd")
+	if err != nil {
+		return "/"
+	}
+	defer f.Close()
+
+	s := bufio.NewScanner(f)
+
+	for s.Scan() {
+		if err := s.Err(); err != nil {
+			break
+		}
+
+		line := strings.TrimSpace(s.Text())
+		if line == "" {
+			continue
+		}
+
+		parts := strings.Split(line, ":")
+
+		if len(parts) >= 6 {
+			uid, err := strconv.Atoi(parts[2])
+			if err == nil && uid == myUid {
+				return parts[5]
+			}
+		}
+	}
+
+	// Default to / if we can't get a better value
+	return "/"
+}
diff --git a/vendor/github.com/godbus/dbus/message.go b/vendor/github.com/godbus/dbus/message.go
new file mode 100644
index 000000000..6a925367e
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/message.go
@@ -0,0 +1,353 @@
+package dbus
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"io"
+	"reflect"
+	"strconv"
+)
+
+const protoVersion byte = 1
+
+// Flags represents the possible flags of a D-Bus message.
+type Flags byte
+
+const (
+	// FlagNoReplyExpected signals that the message is not expected to generate
+	// a reply. If this flag is set on outgoing messages, any possible reply
+	// will be discarded.
+	FlagNoReplyExpected Flags = 1 << iota
+	// FlagNoAutoStart signals that the message bus should not automatically
+	// start an application when handling this message.
+	FlagNoAutoStart
+	// FlagAllowInteractiveAuthorization may be set on a method call
+	// message to inform the receiving side that the caller is prepared
+	// to wait for interactive authorization, which might take a
+	// considerable time to complete. For instance, if this flag is set,
+	// it would be appropriate to query the user for passwords or
+	// confirmation via Polkit or a similar framework.
+	FlagAllowInteractiveAuthorization
+)
+
+// Type represents the possible types of a D-Bus message.
+type Type byte
+
+const (
+	TypeMethodCall Type = 1 + iota
+	TypeMethodReply
+	TypeError
+	TypeSignal
+	typeMax
+)
+
+func (t Type) String() string {
+	switch t {
+	case TypeMethodCall:
+		return "method call"
+	case TypeMethodReply:
+		return "reply"
+	case TypeError:
+		return "error"
+	case TypeSignal:
+		return "signal"
+	}
+	return "invalid"
+}
+
+// HeaderField represents the possible byte codes for the headers
+// of a D-Bus message.
+type HeaderField byte
+
+const (
+	FieldPath HeaderField = 1 + iota
+	FieldInterface
+	FieldMember
+	FieldErrorName
+	FieldReplySerial
+	FieldDestination
+	FieldSender
+	FieldSignature
+	FieldUnixFDs
+	fieldMax
+)
+
+// An InvalidMessageError describes the reason why a D-Bus message is regarded as
+// invalid.
+type InvalidMessageError string
+
+func (e InvalidMessageError) Error() string {
+	return "dbus: invalid message: " + string(e)
+}
+
+// fieldType are the types of the various header fields.
+var fieldTypes = [fieldMax]reflect.Type{
+	FieldPath:        objectPathType,
+	FieldInterface:   stringType,
+	FieldMember:      stringType,
+	FieldErrorName:   stringType,
+	FieldReplySerial: uint32Type,
+	FieldDestination: stringType,
+	FieldSender:      stringType,
+	FieldSignature:   signatureType,
+	FieldUnixFDs:     uint32Type,
+}
+
+// requiredFields lists the header fields that are required by the different
+// message types.
+var requiredFields = [typeMax][]HeaderField{
+	TypeMethodCall:  {FieldPath, FieldMember},
+	TypeMethodReply: {FieldReplySerial},
+	TypeError:       {FieldErrorName, FieldReplySerial},
+	TypeSignal:      {FieldPath, FieldInterface, FieldMember},
+}
+
+// Message represents a single D-Bus message.
+type Message struct {
+	Type
+	Flags
+	Headers map[HeaderField]Variant
+	Body    []interface{}
+
+	serial uint32
+}
+
+type header struct {
+	Field byte
+	Variant
+}
+
+// DecodeMessage tries to decode a single message in the D-Bus wire format
+// from the given reader. The byte order is figured out from the first byte.
+// The possibly returned error can be an error of the underlying reader, an
+// InvalidMessageError or a FormatError.
+func DecodeMessage(rd io.Reader) (msg *Message, err error) {
+	var order binary.ByteOrder
+	var hlength, length uint32
+	var typ, flags, proto byte
+	var headers []header
+
+	b := make([]byte, 1)
+	_, err = rd.Read(b)
+	if err != nil {
+		return
+	}
+	switch b[0] {
+	case 'l':
+		order = binary.LittleEndian
+	case 'B':
+		order = binary.BigEndian
+	default:
+		return nil, InvalidMessageError("invalid byte order")
+	}
+
+	dec := newDecoder(rd, order)
+	dec.pos = 1
+
+	msg = new(Message)
+	vs, err := dec.Decode(Signature{"yyyuu"})
+	if err != nil {
+		return nil, err
+	}
+	if err = Store(vs, &typ, &flags, &proto, &length, &msg.serial); err != nil {
+		return nil, err
+	}
+	msg.Type = Type(typ)
+	msg.Flags = Flags(flags)
+
+	// get the header length separately because we need it later
+	b = make([]byte, 4)
+	_, err = io.ReadFull(rd, b)
+	if err != nil {
+		return nil, err
+	}
+	binary.Read(bytes.NewBuffer(b), order, &hlength)
+	if hlength+length+16 > 1<<27 {
+		return nil, InvalidMessageError("message is too long")
+	}
+	dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order)
+	dec.pos = 12
+	vs, err = dec.Decode(Signature{"a(yv)"})
+	if err != nil {
+		return nil, err
+	}
+	if err = Store(vs, &headers); err != nil {
+		return nil, err
+	}
+
+	msg.Headers = make(map[HeaderField]Variant)
+	for _, v := range headers {
+		msg.Headers[HeaderField(v.Field)] = v.Variant
+	}
+
+	dec.align(8)
+	body := make([]byte, int(length))
+	if length != 0 {
+		_, err := io.ReadFull(rd, body)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if err = msg.IsValid(); err != nil {
+		return nil, err
+	}
+	sig, _ := msg.Headers[FieldSignature].value.(Signature)
+	if sig.str != "" {
+		buf := bytes.NewBuffer(body)
+		dec = newDecoder(buf, order)
+		vs, err := dec.Decode(sig)
+		if err != nil {
+			return nil, err
+		}
+		msg.Body = vs
+	}
+
+	return
+}
+
+// EncodeTo encodes and sends a message to the given writer. The byte order must
+// be either binary.LittleEndian or binary.BigEndian. If the message is not
+// valid or an error occurs when writing, an error is returned.
+func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error {
+	if err := msg.IsValid(); err != nil {
+		return err
+	}
+	var vs [7]interface{}
+	switch order {
+	case binary.LittleEndian:
+		vs[0] = byte('l')
+	case binary.BigEndian:
+		vs[0] = byte('B')
+	default:
+		return errors.New("dbus: invalid byte order")
+	}
+	body := new(bytes.Buffer)
+	enc := newEncoder(body, order)
+	if len(msg.Body) != 0 {
+		enc.Encode(msg.Body...)
+	}
+	vs[1] = msg.Type
+	vs[2] = msg.Flags
+	vs[3] = protoVersion
+	vs[4] = uint32(len(body.Bytes()))
+	vs[5] = msg.serial
+	headers := make([]header, 0, len(msg.Headers))
+	for k, v := range msg.Headers {
+		headers = append(headers, header{byte(k), v})
+	}
+	vs[6] = headers
+	var buf bytes.Buffer
+	enc = newEncoder(&buf, order)
+	enc.Encode(vs[:]...)
+	enc.align(8)
+	body.WriteTo(&buf)
+	if buf.Len() > 1<<27 {
+		return InvalidMessageError("message is too long")
+	}
+	if _, err := buf.WriteTo(out); err != nil {
+		return err
+	}
+	return nil
+}
+
+// IsValid checks whether msg is a valid message and returns an
+// InvalidMessageError if it is not.
+func (msg *Message) IsValid() error {
+	if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected|FlagAllowInteractiveAuthorization) != 0 {
+		return InvalidMessageError("invalid flags")
+	}
+	if msg.Type == 0 || msg.Type >= typeMax {
+		return InvalidMessageError("invalid message type")
+	}
+	for k, v := range msg.Headers {
+		if k == 0 || k >= fieldMax {
+			return InvalidMessageError("invalid header")
+		}
+		if reflect.TypeOf(v.value) != fieldTypes[k] {
+			return InvalidMessageError("invalid type of header field")
+		}
+	}
+	for _, v := range requiredFields[msg.Type] {
+		if _, ok := msg.Headers[v]; !ok {
+			return InvalidMessageError("missing required header")
+		}
+	}
+	if path, ok := msg.Headers[FieldPath]; ok {
+		if !path.value.(ObjectPath).IsValid() {
+			return InvalidMessageError("invalid path name")
+		}
+	}
+	if iface, ok := msg.Headers[FieldInterface]; ok {
+		if !isValidInterface(iface.value.(string)) {
+			return InvalidMessageError("invalid interface name")
+		}
+	}
+	if member, ok := msg.Headers[FieldMember]; ok {
+		if !isValidMember(member.value.(string)) {
+			return InvalidMessageError("invalid member name")
+		}
+	}
+	if errname, ok := msg.Headers[FieldErrorName]; ok {
+		if !isValidInterface(errname.value.(string)) {
+			return InvalidMessageError("invalid error name")
+		}
+	}
+	if len(msg.Body) != 0 {
+		if _, ok := msg.Headers[FieldSignature]; !ok {
+			return InvalidMessageError("missing signature")
+		}
+	}
+	return nil
+}
+
+// Serial returns the message's serial number. The returned value is only valid
+// for messages received by eavesdropping.
+func (msg *Message) Serial() uint32 {
+	return msg.serial
+}
+
+// String returns a string representation of a message similar to the format of
+// dbus-monitor.
+func (msg *Message) String() string {
+	if err := msg.IsValid(); err != nil {
+		return "<invalid>"
+	}
+	s := msg.Type.String()
+	if v, ok := msg.Headers[FieldSender]; ok {
+		s += " from " + v.value.(string)
+	}
+	if v, ok := msg.Headers[FieldDestination]; ok {
+		s += " to " + v.value.(string)
+	}
+	s += " serial " + strconv.FormatUint(uint64(msg.serial), 10)
+	if v, ok := msg.Headers[FieldReplySerial]; ok {
+		s += " reply_serial " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
+	}
+	if v, ok := msg.Headers[FieldUnixFDs]; ok {
+		s += " unixfds " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
+	}
+	if v, ok := msg.Headers[FieldPath]; ok {
+		s += " path " + string(v.value.(ObjectPath))
+	}
+	if v, ok := msg.Headers[FieldInterface]; ok {
+		s += " interface " + v.value.(string)
+	}
+	if v, ok := msg.Headers[FieldErrorName]; ok {
+		s += " error " + v.value.(string)
+	}
+	if v, ok := msg.Headers[FieldMember]; ok {
+		s += " member " + v.value.(string)
+	}
+	if len(msg.Body) != 0 {
+		s += "\n"
+	}
+	for i, v := range msg.Body {
+		s += "  " + MakeVariant(v).String()
+		if i != len(msg.Body)-1 {
+			s += "\n"
+		}
+	}
+	return s
+}
diff --git a/vendor/github.com/godbus/dbus/object.go b/vendor/github.com/godbus/dbus/object.go
new file mode 100644
index 000000000..62b52c65e
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/object.go
@@ -0,0 +1,137 @@
+package dbus
+
+import (
+	"errors"
+	"strings"
+)
+
+// BusObject is the interface of a remote object on which methods can be
+// invoked.
+type BusObject interface {
+	Call(method string, flags Flags, args ...interface{}) *Call
+	Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
+	GetProperty(p string) (Variant, error)
+	Destination() string
+	Path() ObjectPath
+}
+
+// Object represents a remote object on which methods can be invoked.
+type Object struct {
+	conn *Conn
+	dest string
+	path ObjectPath
+}
+
+// Call calls a method with (*Object).Go and waits for its reply.
+func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
+	return <-o.Go(method, flags, make(chan *Call, 1), args...).Done
+}
+
+// AddMatchSignal subscribes BusObject to signals from specified interface and
+// method (member).
+func (o *Object) AddMatchSignal(iface, member string) *Call {
+	return o.Call(
+		"org.freedesktop.DBus.AddMatch",
+		0,
+		"type='signal',interface='"+iface+"',member='"+member+"'",
+	)
+}
+
+// Go calls a method with the given arguments asynchronously. It returns a
+// Call structure representing this method call. The passed channel will
+// return the same value once the call is done. If ch is nil, a new channel
+// will be allocated. Otherwise, ch has to be buffered or Go will panic.
+//
+// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure
+// is returned with any error in Err and a closed channel in Done containing
+// the returned Call as it's one entry.
+//
+// If the method parameter contains a dot ('.'), the part before the last dot
+// specifies the interface on which the method is called.
+func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
+	iface := ""
+	i := strings.LastIndex(method, ".")
+	if i != -1 {
+		iface = method[:i]
+	}
+	method = method[i+1:]
+	msg := new(Message)
+	msg.Type = TypeMethodCall
+	msg.serial = o.conn.getSerial()
+	msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected)
+	msg.Headers = make(map[HeaderField]Variant)
+	msg.Headers[FieldPath] = MakeVariant(o.path)
+	msg.Headers[FieldDestination] = MakeVariant(o.dest)
+	msg.Headers[FieldMember] = MakeVariant(method)
+	if iface != "" {
+		msg.Headers[FieldInterface] = MakeVariant(iface)
+	}
+	msg.Body = args
+	if len(args) > 0 {
+		msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...))
+	}
+	if msg.Flags&FlagNoReplyExpected == 0 {
+		if ch == nil {
+			ch = make(chan *Call, 10)
+		} else if cap(ch) == 0 {
+			panic("dbus: unbuffered channel passed to (*Object).Go")
+		}
+		call := &Call{
+			Destination: o.dest,
+			Path:        o.path,
+			Method:      method,
+			Args:        args,
+			Done:        ch,
+		}
+		o.conn.calls.track(msg.serial, call)
+		o.conn.sendMessageAndIfClosed(msg, func() {
+			call.Err = ErrClosed
+			call.Done <- call
+		})
+		return call
+	}
+	done := make(chan *Call, 1)
+	call := &Call{
+		Err:  nil,
+		Done: done,
+	}
+	defer func() {
+		call.Done <- call
+		close(done)
+	}()
+	o.conn.sendMessageAndIfClosed(msg, func() {
+		call.Err = ErrClosed
+	})
+	return call
+}
+
+// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given
+// object. The property name must be given in interface.member notation.
+func (o *Object) GetProperty(p string) (Variant, error) {
+	idx := strings.LastIndex(p, ".")
+	if idx == -1 || idx+1 == len(p) {
+		return Variant{}, errors.New("dbus: invalid property " + p)
+	}
+
+	iface := p[:idx]
+	prop := p[idx+1:]
+
+	result := Variant{}
+	err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result)
+
+	if err != nil {
+		return Variant{}, err
+	}
+
+	return result, nil
+}
+
+// Destination returns the destination that calls on (o *Object) are sent to.
+func (o *Object) Destination() string {
+	return o.dest
+}
+
+// Path returns the path that calls on (o *Object") are sent to.
+func (o *Object) Path() ObjectPath {
+	return o.path
+}
diff --git a/vendor/github.com/godbus/dbus/server_interfaces.go b/vendor/github.com/godbus/dbus/server_interfaces.go
new file mode 100644
index 000000000..091948aef
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/server_interfaces.go
@@ -0,0 +1,89 @@
+package dbus
+
+// Terminator allows a handler to implement a shutdown mechanism that
+// is called when the connection terminates.
+type Terminator interface {
+	Terminate()
+}
+
+// Handler is the representation of a D-Bus Application.
+//
+// The Handler must have a way to lookup objects given
+// an ObjectPath. The returned object must implement the
+// ServerObject interface.
+type Handler interface {
+	LookupObject(path ObjectPath) (ServerObject, bool)
+}
+
+// ServerObject is the representation of an D-Bus Object.
+//
+// Objects are registered at a path for a given Handler.
+// The Objects implement D-Bus interfaces. The semantics
+// of Interface lookup is up to the implementation of
+// the ServerObject. The ServerObject implementation may
+// choose to implement empty string as a valid interface
+// represeting all methods or not per the D-Bus specification.
+type ServerObject interface {
+	LookupInterface(name string) (Interface, bool)
+}
+
+// An Interface is the representation of a D-Bus Interface.
+//
+// Interfaces are a grouping of methods implemented by the Objects.
+// Interfaces are responsible for routing method calls.
+type Interface interface {
+	LookupMethod(name string) (Method, bool)
+}
+
+// A Method represents the exposed methods on D-Bus.
+type Method interface {
+	// Call requires that all arguments are decoded before being passed to it.
+	Call(args ...interface{}) ([]interface{}, error)
+	NumArguments() int
+	NumReturns() int
+	// ArgumentValue returns a representative value for the argument at position
+	// it should be of the proper type. reflect.Zero would be a good mechanism
+	// to use for this Value.
+	ArgumentValue(position int) interface{}
+	// ReturnValue returns a representative value for the return at position
+	// it should be of the proper type. reflect.Zero would be a good mechanism
+	// to use for this Value.
+	ReturnValue(position int) interface{}
+}
+
+// An Argument Decoder can decode arguments using the non-standard mechanism
+//
+// If a method implements this interface then the non-standard
+// decoder will be used.
+//
+// Method arguments must be decoded from the message.
+// The mechanism for doing this will vary based on the
+// implementation of the method. A normal approach is provided
+// as part of this library, but may be replaced with
+// any other decoding scheme.
+type ArgumentDecoder interface {
+	// To decode the arguments of a method the sender and message are
+	// provided incase the semantics of the implementer provides access
+	// to these as part of the method invocation.
+	DecodeArguments(conn *Conn, sender string, msg *Message, args []interface{}) ([]interface{}, error)
+}
+
+// A SignalHandler is responsible for delivering a signal.
+//
+// Signal delivery may be changed from the default channel
+// based approach by Handlers implementing the SignalHandler
+// interface.
+type SignalHandler interface {
+	DeliverSignal(iface, name string, signal *Signal)
+}
+
+// A DBusError is used to convert a generic object to a D-Bus error.
+//
+// Any custom error mechanism may implement this interface to provide
+// a custom encoding of the error on D-Bus. By default if a normal
+// error is returned, it will be encoded as the generic
+// "org.freedesktop.DBus.Error.Failed" error. By implementing this
+// interface as well a custom encoding may be provided.
+type DBusError interface {
+	DBusError() (string, []interface{})
+}
diff --git a/vendor/github.com/godbus/dbus/sig.go b/vendor/github.com/godbus/dbus/sig.go
new file mode 100644
index 000000000..c1b809202
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/sig.go
@@ -0,0 +1,259 @@
+package dbus
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+)
+
+var sigToType = map[byte]reflect.Type{
+	'y': byteType,
+	'b': boolType,
+	'n': int16Type,
+	'q': uint16Type,
+	'i': int32Type,
+	'u': uint32Type,
+	'x': int64Type,
+	't': uint64Type,
+	'd': float64Type,
+	's': stringType,
+	'g': signatureType,
+	'o': objectPathType,
+	'v': variantType,
+	'h': unixFDIndexType,
+}
+
+// Signature represents a correct type signature as specified by the D-Bus
+// specification. The zero value represents the empty signature, "".
+type Signature struct {
+	str string
+}
+
+// SignatureOf returns the concatenation of all the signatures of the given
+// values. It panics if one of them is not representable in D-Bus.
+func SignatureOf(vs ...interface{}) Signature {
+	var s string
+	for _, v := range vs {
+		s += getSignature(reflect.TypeOf(v))
+	}
+	return Signature{s}
+}
+
+// SignatureOfType returns the signature of the given type. It panics if the
+// type is not representable in D-Bus.
+func SignatureOfType(t reflect.Type) Signature {
+	return Signature{getSignature(t)}
+}
+
+// getSignature returns the signature of the given type and panics on unknown types.
+func getSignature(t reflect.Type) string {
+	// handle simple types first
+	switch t.Kind() {
+	case reflect.Uint8:
+		return "y"
+	case reflect.Bool:
+		return "b"
+	case reflect.Int16:
+		return "n"
+	case reflect.Uint16:
+		return "q"
+	case reflect.Int, reflect.Int32:
+		if t == unixFDType {
+			return "h"
+		}
+		return "i"
+	case reflect.Uint, reflect.Uint32:
+		if t == unixFDIndexType {
+			return "h"
+		}
+		return "u"
+	case reflect.Int64:
+		return "x"
+	case reflect.Uint64:
+		return "t"
+	case reflect.Float64:
+		return "d"
+	case reflect.Ptr:
+		return getSignature(t.Elem())
+	case reflect.String:
+		if t == objectPathType {
+			return "o"
+		}
+		return "s"
+	case reflect.Struct:
+		if t == variantType {
+			return "v"
+		} else if t == signatureType {
+			return "g"
+		}
+		var s string
+		for i := 0; i < t.NumField(); i++ {
+			field := t.Field(i)
+			if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
+				s += getSignature(t.Field(i).Type)
+			}
+		}
+		return "(" + s + ")"
+	case reflect.Array, reflect.Slice:
+		return "a" + getSignature(t.Elem())
+	case reflect.Map:
+		if !isKeyType(t.Key()) {
+			panic(InvalidTypeError{t})
+		}
+		return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}"
+	case reflect.Interface:
+		return "v"
+	}
+	panic(InvalidTypeError{t})
+}
+
+// ParseSignature returns the signature represented by this string, or a
+// SignatureError if the string is not a valid signature.
+func ParseSignature(s string) (sig Signature, err error) {
+	if len(s) == 0 {
+		return
+	}
+	if len(s) > 255 {
+		return Signature{""}, SignatureError{s, "too long"}
+	}
+	sig.str = s
+	for err == nil && len(s) != 0 {
+		err, s = validSingle(s, 0)
+	}
+	if err != nil {
+		sig = Signature{""}
+	}
+
+	return
+}
+
+// ParseSignatureMust behaves like ParseSignature, except that it panics if s
+// is not valid.
+func ParseSignatureMust(s string) Signature {
+	sig, err := ParseSignature(s)
+	if err != nil {
+		panic(err)
+	}
+	return sig
+}
+
+// Empty retruns whether the signature is the empty signature.
+func (s Signature) Empty() bool {
+	return s.str == ""
+}
+
+// Single returns whether the signature represents a single, complete type.
+func (s Signature) Single() bool {
+	err, r := validSingle(s.str, 0)
+	return err != nil && r == ""
+}
+
+// String returns the signature's string representation.
+func (s Signature) String() string {
+	return s.str
+}
+
+// A SignatureError indicates that a signature passed to a function or received
+// on a connection is not a valid signature.
+type SignatureError struct {
+	Sig    string
+	Reason string
+}
+
+func (e SignatureError) Error() string {
+	return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
+}
+
+// Try to read a single type from this string. If it was successful, err is nil
+// and rem is the remaining unparsed part. Otherwise, err is a non-nil
+// SignatureError and rem is "". depth is the current recursion depth which may
+// not be greater than 64 and should be given as 0 on the first call.
+func validSingle(s string, depth int) (err error, rem string) {
+	if s == "" {
+		return SignatureError{Sig: s, Reason: "empty signature"}, ""
+	}
+	if depth > 64 {
+		return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
+	}
+	switch s[0] {
+	case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h':
+		return nil, s[1:]
+	case 'a':
+		if len(s) > 1 && s[1] == '{' {
+			i := findMatching(s[1:], '{', '}')
+			if i == -1 {
+				return SignatureError{Sig: s, Reason: "unmatched '{'"}, ""
+			}
+			i++
+			rem = s[i+1:]
+			s = s[2:i]
+			if err, _ = validSingle(s[:1], depth+1); err != nil {
+				return err, ""
+			}
+			err, nr := validSingle(s[1:], depth+1)
+			if err != nil {
+				return err, ""
+			}
+			if nr != "" {
+				return SignatureError{Sig: s, Reason: "too many types in dict"}, ""
+			}
+			return nil, rem
+		}
+		return validSingle(s[1:], depth+1)
+	case '(':
+		i := findMatching(s, '(', ')')
+		if i == -1 {
+			return SignatureError{Sig: s, Reason: "unmatched ')'"}, ""
+		}
+		rem = s[i+1:]
+		s = s[1:i]
+		for err == nil && s != "" {
+			err, s = validSingle(s, depth+1)
+		}
+		if err != nil {
+			rem = ""
+		}
+		return
+	}
+	return SignatureError{Sig: s, Reason: "invalid type character"}, ""
+}
+
+func findMatching(s string, left, right rune) int {
+	n := 0
+	for i, v := range s {
+		if v == left {
+			n++
+		} else if v == right {
+			n--
+		}
+		if n == 0 {
+			return i
+		}
+	}
+	return -1
+}
+
+// typeFor returns the type of the given signature. It ignores any left over
+// characters and panics if s doesn't start with a valid type signature.
+func typeFor(s string) (t reflect.Type) {
+	err, _ := validSingle(s, 0)
+	if err != nil {
+		panic(err)
+	}
+
+	if t, ok := sigToType[s[0]]; ok {
+		return t
+	}
+	switch s[0] {
+	case 'a':
+		if s[1] == '{' {
+			i := strings.LastIndex(s, "}")
+			t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i]))
+		} else {
+			t = reflect.SliceOf(typeFor(s[1:]))
+		}
+	case '(':
+		t = interfacesType
+	}
+	return
+}
diff --git a/vendor/github.com/godbus/dbus/transport_darwin.go b/vendor/github.com/godbus/dbus/transport_darwin.go
new file mode 100644
index 000000000..1bba0d6bf
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_darwin.go
@@ -0,0 +1,6 @@
+package dbus
+
+func (t *unixTransport) SendNullByte() error {
+	_, err := t.Write([]byte{0})
+	return err
+}
diff --git a/vendor/github.com/godbus/dbus/transport_generic.go b/vendor/github.com/godbus/dbus/transport_generic.go
new file mode 100644
index 000000000..3fad859a6
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_generic.go
@@ -0,0 +1,50 @@
+package dbus
+
+import (
+	"encoding/binary"
+	"errors"
+	"io"
+	"unsafe"
+)
+
+var nativeEndian binary.ByteOrder
+
+func detectEndianness() binary.ByteOrder {
+	var x uint32 = 0x01020304
+		if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
+		return binary.BigEndian
+	}
+	return binary.LittleEndian
+}
+
+func init() {
+	nativeEndian = detectEndianness()
+}
+
+type genericTransport struct {
+	io.ReadWriteCloser
+}
+
+func (t genericTransport) SendNullByte() error {
+	_, err := t.Write([]byte{0})
+	return err
+}
+
+func (t genericTransport) SupportsUnixFDs() bool {
+	return false
+}
+
+func (t genericTransport) EnableUnixFDs() {}
+
+func (t genericTransport) ReadMessage() (*Message, error) {
+	return DecodeMessage(t)
+}
+
+func (t genericTransport) SendMessage(msg *Message) error {
+	for _, v := range msg.Body {
+		if _, ok := v.(UnixFD); ok {
+			return errors.New("dbus: unix fd passing not enabled")
+		}
+	}
+	return msg.EncodeTo(t, nativeEndian)
+}
diff --git a/vendor/github.com/godbus/dbus/transport_tcp.go b/vendor/github.com/godbus/dbus/transport_tcp.go
new file mode 100644
index 000000000..dd1c8e59c
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_tcp.go
@@ -0,0 +1,43 @@
+//+build !windows
+
+package dbus
+
+import (
+	"errors"
+	"net"
+)
+
+func init() {
+	transports["tcp"] = newTcpTransport
+}
+
+func tcpFamily(keys string) (string, error) {
+	switch getKey(keys, "family") {
+	case "":
+		return "tcp", nil
+	case "ipv4":
+		return "tcp4", nil
+	case "ipv6":
+		return "tcp6", nil
+	default:
+		return "", errors.New("dbus: invalid tcp family (must be ipv4 or ipv6)")
+	}
+}
+
+func newTcpTransport(keys string) (transport, error) {
+	host := getKey(keys, "host")
+	port := getKey(keys, "port")
+	if host == "" || port == "" {
+		return nil, errors.New("dbus: unsupported address (must set host and port)")
+	}
+
+	protocol, err := tcpFamily(keys)
+	if err != nil {
+		return nil, err
+	}
+	socket, err := net.Dial(protocol, net.JoinHostPort(host, port))
+	if err != nil {
+		return nil, err
+	}
+	return NewConn(socket)
+}
diff --git a/vendor/github.com/godbus/dbus/transport_unix.go b/vendor/github.com/godbus/dbus/transport_unix.go
new file mode 100644
index 000000000..e56d5ca90
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_unix.go
@@ -0,0 +1,196 @@
+//+build !windows,!solaris
+
+package dbus
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"io"
+	"net"
+	"syscall"
+)
+
+type oobReader struct {
+	conn *net.UnixConn
+	oob  []byte
+	buf  [4096]byte
+}
+
+func (o *oobReader) Read(b []byte) (n int, err error) {
+	n, oobn, flags, _, err := o.conn.ReadMsgUnix(b, o.buf[:])
+	if err != nil {
+		return n, err
+	}
+	if flags&syscall.MSG_CTRUNC != 0 {
+		return n, errors.New("dbus: control data truncated (too many fds received)")
+	}
+	o.oob = append(o.oob, o.buf[:oobn]...)
+	return n, nil
+}
+
+type unixTransport struct {
+	*net.UnixConn
+	hasUnixFDs bool
+}
+
+func newUnixTransport(keys string) (transport, error) {
+	var err error
+
+	t := new(unixTransport)
+	abstract := getKey(keys, "abstract")
+	path := getKey(keys, "path")
+	switch {
+	case abstract == "" && path == "":
+		return nil, errors.New("dbus: invalid address (neither path nor abstract set)")
+	case abstract != "" && path == "":
+		t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: "@" + abstract, Net: "unix"})
+		if err != nil {
+			return nil, err
+		}
+		return t, nil
+	case abstract == "" && path != "":
+		t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: path, Net: "unix"})
+		if err != nil {
+			return nil, err
+		}
+		return t, nil
+	default:
+		return nil, errors.New("dbus: invalid address (both path and abstract set)")
+	}
+}
+
+func init() {
+	transports["unix"] = newUnixTransport
+}
+
+func (t *unixTransport) EnableUnixFDs() {
+	t.hasUnixFDs = true
+}
+
+func (t *unixTransport) ReadMessage() (*Message, error) {
+	var (
+		blen, hlen uint32
+		csheader   [16]byte
+		headers    []header
+		order      binary.ByteOrder
+		unixfds    uint32
+	)
+	// To be sure that all bytes of out-of-band data are read, we use a special
+	// reader that uses ReadUnix on the underlying connection instead of Read
+	// and gathers the out-of-band data in a buffer.
+	rd := &oobReader{conn: t.UnixConn}
+	// read the first 16 bytes (the part of the header that has a constant size),
+	// from which we can figure out the length of the rest of the message
+	if _, err := io.ReadFull(rd, csheader[:]); err != nil {
+		return nil, err
+	}
+	switch csheader[0] {
+	case 'l':
+		order = binary.LittleEndian
+	case 'B':
+		order = binary.BigEndian
+	default:
+		return nil, InvalidMessageError("invalid byte order")
+	}
+	// csheader[4:8] -> length of message body, csheader[12:16] -> length of
+	// header fields (without alignment)
+	binary.Read(bytes.NewBuffer(csheader[4:8]), order, &blen)
+	binary.Read(bytes.NewBuffer(csheader[12:]), order, &hlen)
+	if hlen%8 != 0 {
+		hlen += 8 - (hlen % 8)
+	}
+
+	// decode headers and look for unix fds
+	headerdata := make([]byte, hlen+4)
+	copy(headerdata, csheader[12:])
+	if _, err := io.ReadFull(t, headerdata[4:]); err != nil {
+		return nil, err
+	}
+	dec := newDecoder(bytes.NewBuffer(headerdata), order)
+	dec.pos = 12
+	vs, err := dec.Decode(Signature{"a(yv)"})
+	if err != nil {
+		return nil, err
+	}
+	Store(vs, &headers)
+	for _, v := range headers {
+		if v.Field == byte(FieldUnixFDs) {
+			unixfds, _ = v.Variant.value.(uint32)
+		}
+	}
+	all := make([]byte, 16+hlen+blen)
+	copy(all, csheader[:])
+	copy(all[16:], headerdata[4:])
+	if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil {
+		return nil, err
+	}
+	if unixfds != 0 {
+		if !t.hasUnixFDs {
+			return nil, errors.New("dbus: got unix fds on unsupported transport")
+		}
+		// read the fds from the OOB data
+		scms, err := syscall.ParseSocketControlMessage(rd.oob)
+		if err != nil {
+			return nil, err
+		}
+		if len(scms) != 1 {
+			return nil, errors.New("dbus: received more than one socket control message")
+		}
+		fds, err := syscall.ParseUnixRights(&scms[0])
+		if err != nil {
+			return nil, err
+		}
+		msg, err := DecodeMessage(bytes.NewBuffer(all))
+		if err != nil {
+			return nil, err
+		}
+		// substitute the values in the message body (which are indices for the
+		// array receiver via OOB) with the actual values
+		for i, v := range msg.Body {
+			if j, ok := v.(UnixFDIndex); ok {
+				if uint32(j) >= unixfds {
+					return nil, InvalidMessageError("invalid index for unix fd")
+				}
+				msg.Body[i] = UnixFD(fds[j])
+			}
+		}
+		return msg, nil
+	}
+	return DecodeMessage(bytes.NewBuffer(all))
+}
+
+func (t *unixTransport) SendMessage(msg *Message) error {
+	fds := make([]int, 0)
+	for i, v := range msg.Body {
+		if fd, ok := v.(UnixFD); ok {
+			msg.Body[i] = UnixFDIndex(len(fds))
+			fds = append(fds, int(fd))
+		}
+	}
+	if len(fds) != 0 {
+		if !t.hasUnixFDs {
+			return errors.New("dbus: unix fd passing not enabled")
+		}
+		msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds)))
+		oob := syscall.UnixRights(fds...)
+		buf := new(bytes.Buffer)
+		msg.EncodeTo(buf, nativeEndian)
+		n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil)
+		if err != nil {
+			return err
+		}
+		if n != buf.Len() || oobn != len(oob) {
+			return io.ErrShortWrite
+		}
+	} else {
+		if err := msg.EncodeTo(t, nativeEndian); err != nil {
+			return nil
+		}
+	}
+	return nil
+}
+
+func (t *unixTransport) SupportsUnixFDs() bool {
+	return true
+}
diff --git a/vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go b/vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go
new file mode 100644
index 000000000..a8cd39395
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go
@@ -0,0 +1,95 @@
+// The UnixCredentials system call is currently only implemented on Linux
+// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
+// https://golang.org/s/go1.4-syscall
+// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys
+
+// Local implementation of the UnixCredentials system call for DragonFly BSD
+
+package dbus
+
+/*
+#include <sys/ucred.h>
+*/
+import "C"
+
+import (
+	"io"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+// http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go
+// http://golang.org/src/pkg/syscall/ztypes_dragonfly_amd64.go
+type Ucred struct {
+	Pid int32
+	Uid uint32
+	Gid uint32
+}
+
+// http://golang.org/src/pkg/syscall/types_linux.go
+// http://golang.org/src/pkg/syscall/types_dragonfly.go
+// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/ucred.h
+const (
+	SizeofUcred = C.sizeof_struct_ucred
+)
+
+// http://golang.org/src/pkg/syscall/sockcmsg_unix.go
+func cmsgAlignOf(salen int) int {
+	// From http://golang.org/src/pkg/syscall/sockcmsg_unix.go
+	//salign := sizeofPtr
+	// NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
+	// still require 32-bit aligned access to network subsystem.
+	//if darwin64Bit || dragonfly64Bit {
+	//	salign = 4
+	//}
+	salign := 4
+	return (salen + salign - 1) & ^(salign - 1)
+}
+
+// http://golang.org/src/pkg/syscall/sockcmsg_unix.go
+func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer {
+	return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(syscall.SizeofCmsghdr)))
+}
+
+// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
+// UnixCredentials encodes credentials into a socket control message
+// for sending to another process. This can be used for
+// authentication.
+func UnixCredentials(ucred *Ucred) []byte {
+	b := make([]byte, syscall.CmsgSpace(SizeofUcred))
+	h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
+	h.Level = syscall.SOL_SOCKET
+	h.Type = syscall.SCM_CREDS
+	h.SetLen(syscall.CmsgLen(SizeofUcred))
+	*((*Ucred)(cmsgData(h))) = *ucred
+	return b
+}
+
+// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
+// ParseUnixCredentials decodes a socket control message that contains
+// credentials in a Ucred structure. To receive such a message, the
+// SO_PASSCRED option must be enabled on the socket.
+func ParseUnixCredentials(m *syscall.SocketControlMessage) (*Ucred, error) {
+	if m.Header.Level != syscall.SOL_SOCKET {
+		return nil, syscall.EINVAL
+	}
+	if m.Header.Type != syscall.SCM_CREDS {
+		return nil, syscall.EINVAL
+	}
+	ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
+	return &ucred, nil
+}
+
+func (t *unixTransport) SendNullByte() error {
+	ucred := &Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())}
+	b := UnixCredentials(ucred)
+	_, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil)
+	if err != nil {
+		return err
+	}
+	if oobn != len(b) {
+		return io.ErrShortWrite
+	}
+	return nil
+}
diff --git a/vendor/github.com/godbus/dbus/transport_unixcred_freebsd.go b/vendor/github.com/godbus/dbus/transport_unixcred_freebsd.go
new file mode 100644
index 000000000..0fc5b9273
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_unixcred_freebsd.go
@@ -0,0 +1,91 @@
+// The UnixCredentials system call is currently only implemented on Linux
+// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
+// https://golang.org/s/go1.4-syscall
+// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys
+
+// Local implementation of the UnixCredentials system call for FreeBSD
+
+package dbus
+
+/*
+const int sizeofPtr = sizeof(void*);
+#define _WANT_UCRED
+#include <sys/ucred.h>
+*/
+import "C"
+
+import (
+	"io"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+// http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go
+// https://golang.org/src/syscall/ztypes_freebsd_amd64.go
+type Ucred struct {
+	Pid int32
+	Uid uint32
+	Gid uint32
+}
+
+// http://golang.org/src/pkg/syscall/types_linux.go
+// https://golang.org/src/syscall/types_freebsd.go
+// https://github.com/freebsd/freebsd/blob/master/sys/sys/ucred.h
+const (
+	SizeofUcred = C.sizeof_struct_ucred
+)
+
+// http://golang.org/src/pkg/syscall/sockcmsg_unix.go
+func cmsgAlignOf(salen int) int {
+	salign := C.sizeofPtr
+
+	return (salen + salign - 1) & ^(salign - 1)
+}
+
+// http://golang.org/src/pkg/syscall/sockcmsg_unix.go
+func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer {
+	return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(syscall.SizeofCmsghdr)))
+}
+
+// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
+// UnixCredentials encodes credentials into a socket control message
+// for sending to another process. This can be used for
+// authentication.
+func UnixCredentials(ucred *Ucred) []byte {
+	b := make([]byte, syscall.CmsgSpace(SizeofUcred))
+	h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
+	h.Level = syscall.SOL_SOCKET
+	h.Type = syscall.SCM_CREDS
+	h.SetLen(syscall.CmsgLen(SizeofUcred))
+	*((*Ucred)(cmsgData(h))) = *ucred
+	return b
+}
+
+// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
+// ParseUnixCredentials decodes a socket control message that contains
+// credentials in a Ucred structure. To receive such a message, the
+// SO_PASSCRED option must be enabled on the socket.
+func ParseUnixCredentials(m *syscall.SocketControlMessage) (*Ucred, error) {
+	if m.Header.Level != syscall.SOL_SOCKET {
+		return nil, syscall.EINVAL
+	}
+	if m.Header.Type != syscall.SCM_CREDS {
+		return nil, syscall.EINVAL
+	}
+	ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
+	return &ucred, nil
+}
+
+func (t *unixTransport) SendNullByte() error {
+	ucred := &Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())}
+	b := UnixCredentials(ucred)
+	_, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil)
+	if err != nil {
+		return err
+	}
+	if oobn != len(b) {
+		return io.ErrShortWrite
+	}
+	return nil
+}
diff --git a/vendor/github.com/godbus/dbus/transport_unixcred_linux.go b/vendor/github.com/godbus/dbus/transport_unixcred_linux.go
new file mode 100644
index 000000000..d9dfdf698
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_unixcred_linux.go
@@ -0,0 +1,25 @@
+// The UnixCredentials system call is currently only implemented on Linux
+// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
+// https://golang.org/s/go1.4-syscall
+// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys
+
+package dbus
+
+import (
+	"io"
+	"os"
+	"syscall"
+)
+
+func (t *unixTransport) SendNullByte() error {
+	ucred := &syscall.Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())}
+	b := syscall.UnixCredentials(ucred)
+	_, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil)
+	if err != nil {
+		return err
+	}
+	if oobn != len(b) {
+		return io.ErrShortWrite
+	}
+	return nil
+}
diff --git a/vendor/github.com/godbus/dbus/transport_unixcred_openbsd.go b/vendor/github.com/godbus/dbus/transport_unixcred_openbsd.go
new file mode 100644
index 000000000..af7bafdf9
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_unixcred_openbsd.go
@@ -0,0 +1,14 @@
+package dbus
+
+import "io"
+
+func (t *unixTransport) SendNullByte() error {
+	n, _, err := t.UnixConn.WriteMsgUnix([]byte{0}, nil, nil)
+	if err != nil {
+		return err
+	}
+	if n != 1 {
+		return io.ErrShortWrite
+	}
+	return nil
+}
diff --git a/vendor/github.com/godbus/dbus/variant.go b/vendor/github.com/godbus/dbus/variant.go
new file mode 100644
index 000000000..0ca123b01
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/variant.go
@@ -0,0 +1,144 @@
+package dbus
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"sort"
+	"strconv"
+)
+
+// Variant represents the D-Bus variant type.
+type Variant struct {
+	sig   Signature
+	value interface{}
+}
+
+// MakeVariant converts the given value to a Variant. It panics if v cannot be
+// represented as a D-Bus type.
+func MakeVariant(v interface{}) Variant {
+	return MakeVariantWithSignature(v, SignatureOf(v))
+}
+
+// MakeVariantWithSignature converts the given value to a Variant.
+func MakeVariantWithSignature(v interface{}, s Signature) Variant {
+	return Variant{s, v}
+}
+
+// ParseVariant parses the given string as a variant as described at
+// https://developer.gnome.org/glib/unstable/gvariant-text.html. If sig is not
+// empty, it is taken to be the expected signature for the variant.
+func ParseVariant(s string, sig Signature) (Variant, error) {
+	tokens := varLex(s)
+	p := &varParser{tokens: tokens}
+	n, err := varMakeNode(p)
+	if err != nil {
+		return Variant{}, err
+	}
+	if sig.str == "" {
+		sig, err = varInfer(n)
+		if err != nil {
+			return Variant{}, err
+		}
+	}
+	v, err := n.Value(sig)
+	if err != nil {
+		return Variant{}, err
+	}
+	return MakeVariant(v), nil
+}
+
+// format returns a formatted version of v and whether this string can be parsed
+// unambigously.
+func (v Variant) format() (string, bool) {
+	switch v.sig.str[0] {
+	case 'b', 'i':
+		return fmt.Sprint(v.value), true
+	case 'n', 'q', 'u', 'x', 't', 'd', 'h':
+		return fmt.Sprint(v.value), false
+	case 's':
+		return strconv.Quote(v.value.(string)), true
+	case 'o':
+		return strconv.Quote(string(v.value.(ObjectPath))), false
+	case 'g':
+		return strconv.Quote(v.value.(Signature).str), false
+	case 'v':
+		s, unamb := v.value.(Variant).format()
+		if !unamb {
+			return "<@" + v.value.(Variant).sig.str + " " + s + ">", true
+		}
+		return "<" + s + ">", true
+	case 'y':
+		return fmt.Sprintf("%#x", v.value.(byte)), false
+	}
+	rv := reflect.ValueOf(v.value)
+	switch rv.Kind() {
+	case reflect.Slice:
+		if rv.Len() == 0 {
+			return "[]", false
+		}
+		unamb := true
+		buf := bytes.NewBuffer([]byte("["))
+		for i := 0; i < rv.Len(); i++ {
+			// TODO: slooow
+			s, b := MakeVariant(rv.Index(i).Interface()).format()
+			unamb = unamb && b
+			buf.WriteString(s)
+			if i != rv.Len()-1 {
+				buf.WriteString(", ")
+			}
+		}
+		buf.WriteByte(']')
+		return buf.String(), unamb
+	case reflect.Map:
+		if rv.Len() == 0 {
+			return "{}", false
+		}
+		unamb := true
+		var buf bytes.Buffer
+		kvs := make([]string, rv.Len())
+		for i, k := range rv.MapKeys() {
+			s, b := MakeVariant(k.Interface()).format()
+			unamb = unamb && b
+			buf.Reset()
+			buf.WriteString(s)
+			buf.WriteString(": ")
+			s, b = MakeVariant(rv.MapIndex(k).Interface()).format()
+			unamb = unamb && b
+			buf.WriteString(s)
+			kvs[i] = buf.String()
+		}
+		buf.Reset()
+		buf.WriteByte('{')
+		sort.Strings(kvs)
+		for i, kv := range kvs {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			buf.WriteString(kv)
+		}
+		buf.WriteByte('}')
+		return buf.String(), unamb
+	}
+	return `"INVALID"`, true
+}
+
+// Signature returns the D-Bus signature of the underlying value of v.
+func (v Variant) Signature() Signature {
+	return v.sig
+}
+
+// String returns the string representation of the underlying value of v as
+// described at https://developer.gnome.org/glib/unstable/gvariant-text.html.
+func (v Variant) String() string {
+	s, unamb := v.format()
+	if !unamb {
+		return "@" + v.sig.str + " " + s
+	}
+	return s
+}
+
+// Value returns the underlying value of v.
+func (v Variant) Value() interface{} {
+	return v.value
+}
diff --git a/vendor/github.com/godbus/dbus/variant_lexer.go b/vendor/github.com/godbus/dbus/variant_lexer.go
new file mode 100644
index 000000000..332007d6f
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/variant_lexer.go
@@ -0,0 +1,284 @@
+package dbus
+
+import (
+	"fmt"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+// Heavily inspired by the lexer from text/template.
+
+type varToken struct {
+	typ varTokenType
+	val string
+}
+
+type varTokenType byte
+
+const (
+	tokEOF varTokenType = iota
+	tokError
+	tokNumber
+	tokString
+	tokBool
+	tokArrayStart
+	tokArrayEnd
+	tokDictStart
+	tokDictEnd
+	tokVariantStart
+	tokVariantEnd
+	tokComma
+	tokColon
+	tokType
+	tokByteString
+)
+
+type varLexer struct {
+	input  string
+	start  int
+	pos    int
+	width  int
+	tokens []varToken
+}
+
+type lexState func(*varLexer) lexState
+
+func varLex(s string) []varToken {
+	l := &varLexer{input: s}
+	l.run()
+	return l.tokens
+}
+
+func (l *varLexer) accept(valid string) bool {
+	if strings.IndexRune(valid, l.next()) >= 0 {
+		return true
+	}
+	l.backup()
+	return false
+}
+
+func (l *varLexer) backup() {
+	l.pos -= l.width
+}
+
+func (l *varLexer) emit(t varTokenType) {
+	l.tokens = append(l.tokens, varToken{t, l.input[l.start:l.pos]})
+	l.start = l.pos
+}
+
+func (l *varLexer) errorf(format string, v ...interface{}) lexState {
+	l.tokens = append(l.tokens, varToken{
+		tokError,
+		fmt.Sprintf(format, v...),
+	})
+	return nil
+}
+
+func (l *varLexer) ignore() {
+	l.start = l.pos
+}
+
+func (l *varLexer) next() rune {
+	var r rune
+
+	if l.pos >= len(l.input) {
+		l.width = 0
+		return -1
+	}
+	r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
+	l.pos += l.width
+	return r
+}
+
+func (l *varLexer) run() {
+	for state := varLexNormal; state != nil; {
+		state = state(l)
+	}
+}
+
+func (l *varLexer) peek() rune {
+	r := l.next()
+	l.backup()
+	return r
+}
+
+func varLexNormal(l *varLexer) lexState {
+	for {
+		r := l.next()
+		switch {
+		case r == -1:
+			l.emit(tokEOF)
+			return nil
+		case r == '[':
+			l.emit(tokArrayStart)
+		case r == ']':
+			l.emit(tokArrayEnd)
+		case r == '{':
+			l.emit(tokDictStart)
+		case r == '}':
+			l.emit(tokDictEnd)
+		case r == '<':
+			l.emit(tokVariantStart)
+		case r == '>':
+			l.emit(tokVariantEnd)
+		case r == ':':
+			l.emit(tokColon)
+		case r == ',':
+			l.emit(tokComma)
+		case r == '\'' || r == '"':
+			l.backup()
+			return varLexString
+		case r == '@':
+			l.backup()
+			return varLexType
+		case unicode.IsSpace(r):
+			l.ignore()
+		case unicode.IsNumber(r) || r == '+' || r == '-':
+			l.backup()
+			return varLexNumber
+		case r == 'b':
+			pos := l.start
+			if n := l.peek(); n == '"' || n == '\'' {
+				return varLexByteString
+			}
+			// not a byte string; try to parse it as a type or bool below
+			l.pos = pos + 1
+			l.width = 1
+			fallthrough
+		default:
+			// either a bool or a type. Try bools first.
+			l.backup()
+			if l.pos+4 <= len(l.input) {
+				if l.input[l.pos:l.pos+4] == "true" {
+					l.pos += 4
+					l.emit(tokBool)
+					continue
+				}
+			}
+			if l.pos+5 <= len(l.input) {
+				if l.input[l.pos:l.pos+5] == "false" {
+					l.pos += 5
+					l.emit(tokBool)
+					continue
+				}
+			}
+			// must be a type.
+			return varLexType
+		}
+	}
+}
+
+var varTypeMap = map[string]string{
+	"boolean":    "b",
+	"byte":       "y",
+	"int16":      "n",
+	"uint16":     "q",
+	"int32":      "i",
+	"uint32":     "u",
+	"int64":      "x",
+	"uint64":     "t",
+	"double":     "f",
+	"string":     "s",
+	"objectpath": "o",
+	"signature":  "g",
+}
+
+func varLexByteString(l *varLexer) lexState {
+	q := l.next()
+Loop:
+	for {
+		switch l.next() {
+		case '\\':
+			if r := l.next(); r != -1 {
+				break
+			}
+			fallthrough
+		case -1:
+			return l.errorf("unterminated bytestring")
+		case q:
+			break Loop
+		}
+	}
+	l.emit(tokByteString)
+	return varLexNormal
+}
+
+func varLexNumber(l *varLexer) lexState {
+	l.accept("+-")
+	digits := "0123456789"
+	if l.accept("0") {
+		if l.accept("x") {
+			digits = "0123456789abcdefABCDEF"
+		} else {
+			digits = "01234567"
+		}
+	}
+	for strings.IndexRune(digits, l.next()) >= 0 {
+	}
+	l.backup()
+	if l.accept(".") {
+		for strings.IndexRune(digits, l.next()) >= 0 {
+		}
+		l.backup()
+	}
+	if l.accept("eE") {
+		l.accept("+-")
+		for strings.IndexRune("0123456789", l.next()) >= 0 {
+		}
+		l.backup()
+	}
+	if r := l.peek(); unicode.IsLetter(r) {
+		l.next()
+		return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+	}
+	l.emit(tokNumber)
+	return varLexNormal
+}
+
+func varLexString(l *varLexer) lexState {
+	q := l.next()
+Loop:
+	for {
+		switch l.next() {
+		case '\\':
+			if r := l.next(); r != -1 {
+				break
+			}
+			fallthrough
+		case -1:
+			return l.errorf("unterminated string")
+		case q:
+			break Loop
+		}
+	}
+	l.emit(tokString)
+	return varLexNormal
+}
+
+func varLexType(l *varLexer) lexState {
+	at := l.accept("@")
+	for {
+		r := l.next()
+		if r == -1 {
+			break
+		}
+		if unicode.IsSpace(r) {
+			l.backup()
+			break
+		}
+	}
+	if at {
+		if _, err := ParseSignature(l.input[l.start+1 : l.pos]); err != nil {
+			return l.errorf("%s", err)
+		}
+	} else {
+		if _, ok := varTypeMap[l.input[l.start:l.pos]]; ok {
+			l.emit(tokType)
+			return varLexNormal
+		}
+		return l.errorf("unrecognized type %q", l.input[l.start:l.pos])
+	}
+	l.emit(tokType)
+	return varLexNormal
+}
diff --git a/vendor/github.com/godbus/dbus/variant_parser.go b/vendor/github.com/godbus/dbus/variant_parser.go
new file mode 100644
index 000000000..d20f5da6d
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/variant_parser.go
@@ -0,0 +1,817 @@
+package dbus
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"reflect"
+	"strconv"
+	"strings"
+	"unicode/utf8"
+)
+
+type varParser struct {
+	tokens []varToken
+	i      int
+}
+
+func (p *varParser) backup() {
+	p.i--
+}
+
+func (p *varParser) next() varToken {
+	if p.i < len(p.tokens) {
+		t := p.tokens[p.i]
+		p.i++
+		return t
+	}
+	return varToken{typ: tokEOF}
+}
+
+type varNode interface {
+	Infer() (Signature, error)
+	String() string
+	Sigs() sigSet
+	Value(Signature) (interface{}, error)
+}
+
+func varMakeNode(p *varParser) (varNode, error) {
+	var sig Signature
+
+	for {
+		t := p.next()
+		switch t.typ {
+		case tokEOF:
+			return nil, io.ErrUnexpectedEOF
+		case tokError:
+			return nil, errors.New(t.val)
+		case tokNumber:
+			return varMakeNumNode(t, sig)
+		case tokString:
+			return varMakeStringNode(t, sig)
+		case tokBool:
+			if sig.str != "" && sig.str != "b" {
+				return nil, varTypeError{t.val, sig}
+			}
+			b, err := strconv.ParseBool(t.val)
+			if err != nil {
+				return nil, err
+			}
+			return boolNode(b), nil
+		case tokArrayStart:
+			return varMakeArrayNode(p, sig)
+		case tokVariantStart:
+			return varMakeVariantNode(p, sig)
+		case tokDictStart:
+			return varMakeDictNode(p, sig)
+		case tokType:
+			if sig.str != "" {
+				return nil, errors.New("unexpected type annotation")
+			}
+			if t.val[0] == '@' {
+				sig.str = t.val[1:]
+			} else {
+				sig.str = varTypeMap[t.val]
+			}
+		case tokByteString:
+			if sig.str != "" && sig.str != "ay" {
+				return nil, varTypeError{t.val, sig}
+			}
+			b, err := varParseByteString(t.val)
+			if err != nil {
+				return nil, err
+			}
+			return byteStringNode(b), nil
+		default:
+			return nil, fmt.Errorf("unexpected %q", t.val)
+		}
+	}
+}
+
+type varTypeError struct {
+	val string
+	sig Signature
+}
+
+func (e varTypeError) Error() string {
+	return fmt.Sprintf("dbus: can't parse %q as type %q", e.val, e.sig.str)
+}
+
+type sigSet map[Signature]bool
+
+func (s sigSet) Empty() bool {
+	return len(s) == 0
+}
+
+func (s sigSet) Intersect(s2 sigSet) sigSet {
+	r := make(sigSet)
+	for k := range s {
+		if s2[k] {
+			r[k] = true
+		}
+	}
+	return r
+}
+
+func (s sigSet) Single() (Signature, bool) {
+	if len(s) == 1 {
+		for k := range s {
+			return k, true
+		}
+	}
+	return Signature{}, false
+}
+
+func (s sigSet) ToArray() sigSet {
+	r := make(sigSet, len(s))
+	for k := range s {
+		r[Signature{"a" + k.str}] = true
+	}
+	return r
+}
+
+type numNode struct {
+	sig Signature
+	str string
+	val interface{}
+}
+
+var numSigSet = sigSet{
+	Signature{"y"}: true,
+	Signature{"n"}: true,
+	Signature{"q"}: true,
+	Signature{"i"}: true,
+	Signature{"u"}: true,
+	Signature{"x"}: true,
+	Signature{"t"}: true,
+	Signature{"d"}: true,
+}
+
+func (n numNode) Infer() (Signature, error) {
+	if strings.ContainsAny(n.str, ".e") {
+		return Signature{"d"}, nil
+	}
+	return Signature{"i"}, nil
+}
+
+func (n numNode) String() string {
+	return n.str
+}
+
+func (n numNode) Sigs() sigSet {
+	if n.sig.str != "" {
+		return sigSet{n.sig: true}
+	}
+	if strings.ContainsAny(n.str, ".e") {
+		return sigSet{Signature{"d"}: true}
+	}
+	return numSigSet
+}
+
+func (n numNode) Value(sig Signature) (interface{}, error) {
+	if n.sig.str != "" && n.sig != sig {
+		return nil, varTypeError{n.str, sig}
+	}
+	if n.val != nil {
+		return n.val, nil
+	}
+	return varNumAs(n.str, sig)
+}
+
+func varMakeNumNode(tok varToken, sig Signature) (varNode, error) {
+	if sig.str == "" {
+		return numNode{str: tok.val}, nil
+	}
+	num, err := varNumAs(tok.val, sig)
+	if err != nil {
+		return nil, err
+	}
+	return numNode{sig: sig, val: num}, nil
+}
+
+func varNumAs(s string, sig Signature) (interface{}, error) {
+	isUnsigned := false
+	size := 32
+	switch sig.str {
+	case "n":
+		size = 16
+	case "i":
+	case "x":
+		size = 64
+	case "y":
+		size = 8
+		isUnsigned = true
+	case "q":
+		size = 16
+		isUnsigned = true
+	case "u":
+		isUnsigned = true
+	case "t":
+		size = 64
+		isUnsigned = true
+	case "d":
+		d, err := strconv.ParseFloat(s, 64)
+		if err != nil {
+			return nil, err
+		}
+		return d, nil
+	default:
+		return nil, varTypeError{s, sig}
+	}
+	base := 10
+	if strings.HasPrefix(s, "0x") {
+		base = 16
+		s = s[2:]
+	}
+	if strings.HasPrefix(s, "0") && len(s) != 1 {
+		base = 8
+		s = s[1:]
+	}
+	if isUnsigned {
+		i, err := strconv.ParseUint(s, base, size)
+		if err != nil {
+			return nil, err
+		}
+		var v interface{} = i
+		switch sig.str {
+		case "y":
+			v = byte(i)
+		case "q":
+			v = uint16(i)
+		case "u":
+			v = uint32(i)
+		}
+		return v, nil
+	}
+	i, err := strconv.ParseInt(s, base, size)
+	if err != nil {
+		return nil, err
+	}
+	var v interface{} = i
+	switch sig.str {
+	case "n":
+		v = int16(i)
+	case "i":
+		v = int32(i)
+	}
+	return v, nil
+}
+
+type stringNode struct {
+	sig Signature
+	str string      // parsed
+	val interface{} // has correct type
+}
+
+var stringSigSet = sigSet{
+	Signature{"s"}: true,
+	Signature{"g"}: true,
+	Signature{"o"}: true,
+}
+
+func (n stringNode) Infer() (Signature, error) {
+	return Signature{"s"}, nil
+}
+
+func (n stringNode) String() string {
+	return n.str
+}
+
+func (n stringNode) Sigs() sigSet {
+	if n.sig.str != "" {
+		return sigSet{n.sig: true}
+	}
+	return stringSigSet
+}
+
+func (n stringNode) Value(sig Signature) (interface{}, error) {
+	if n.sig.str != "" && n.sig != sig {
+		return nil, varTypeError{n.str, sig}
+	}
+	if n.val != nil {
+		return n.val, nil
+	}
+	switch {
+	case sig.str == "g":
+		return Signature{n.str}, nil
+	case sig.str == "o":
+		return ObjectPath(n.str), nil
+	case sig.str == "s":
+		return n.str, nil
+	default:
+		return nil, varTypeError{n.str, sig}
+	}
+}
+
+func varMakeStringNode(tok varToken, sig Signature) (varNode, error) {
+	if sig.str != "" && sig.str != "s" && sig.str != "g" && sig.str != "o" {
+		return nil, fmt.Errorf("invalid type %q for string", sig.str)
+	}
+	s, err := varParseString(tok.val)
+	if err != nil {
+		return nil, err
+	}
+	n := stringNode{str: s}
+	if sig.str == "" {
+		return stringNode{str: s}, nil
+	}
+	n.sig = sig
+	switch sig.str {
+	case "o":
+		n.val = ObjectPath(s)
+	case "g":
+		n.val = Signature{s}
+	case "s":
+		n.val = s
+	}
+	return n, nil
+}
+
+func varParseString(s string) (string, error) {
+	// quotes are guaranteed to be there
+	s = s[1 : len(s)-1]
+	buf := new(bytes.Buffer)
+	for len(s) != 0 {
+		r, size := utf8.DecodeRuneInString(s)
+		if r == utf8.RuneError && size == 1 {
+			return "", errors.New("invalid UTF-8")
+		}
+		s = s[size:]
+		if r != '\\' {
+			buf.WriteRune(r)
+			continue
+		}
+		r, size = utf8.DecodeRuneInString(s)
+		if r == utf8.RuneError && size == 1 {
+			return "", errors.New("invalid UTF-8")
+		}
+		s = s[size:]
+		switch r {
+		case 'a':
+			buf.WriteRune(0x7)
+		case 'b':
+			buf.WriteRune(0x8)
+		case 'f':
+			buf.WriteRune(0xc)
+		case 'n':
+			buf.WriteRune('\n')
+		case 'r':
+			buf.WriteRune('\r')
+		case 't':
+			buf.WriteRune('\t')
+		case '\n':
+		case 'u':
+			if len(s) < 4 {
+				return "", errors.New("short unicode escape")
+			}
+			r, err := strconv.ParseUint(s[:4], 16, 32)
+			if err != nil {
+				return "", err
+			}
+			buf.WriteRune(rune(r))
+			s = s[4:]
+		case 'U':
+			if len(s) < 8 {
+				return "", errors.New("short unicode escape")
+			}
+			r, err := strconv.ParseUint(s[:8], 16, 32)
+			if err != nil {
+				return "", err
+			}
+			buf.WriteRune(rune(r))
+			s = s[8:]
+		default:
+			buf.WriteRune(r)
+		}
+	}
+	return buf.String(), nil
+}
+
+var boolSigSet = sigSet{Signature{"b"}: true}
+
+type boolNode bool
+
+func (boolNode) Infer() (Signature, error) {
+	return Signature{"b"}, nil
+}
+
+func (b boolNode) String() string {
+	if b {
+		return "true"
+	}
+	return "false"
+}
+
+func (boolNode) Sigs() sigSet {
+	return boolSigSet
+}
+
+func (b boolNode) Value(sig Signature) (interface{}, error) {
+	if sig.str != "b" {
+		return nil, varTypeError{b.String(), sig}
+	}
+	return bool(b), nil
+}
+
+type arrayNode struct {
+	set      sigSet
+	children []varNode
+	val      interface{}
+}
+
+func (n arrayNode) Infer() (Signature, error) {
+	for _, v := range n.children {
+		csig, err := varInfer(v)
+		if err != nil {
+			continue
+		}
+		return Signature{"a" + csig.str}, nil
+	}
+	return Signature{}, fmt.Errorf("can't infer type for %q", n.String())
+}
+
+func (n arrayNode) String() string {
+	s := "["
+	for i, v := range n.children {
+		s += v.String()
+		if i != len(n.children)-1 {
+			s += ", "
+		}
+	}
+	return s + "]"
+}
+
+func (n arrayNode) Sigs() sigSet {
+	return n.set
+}
+
+func (n arrayNode) Value(sig Signature) (interface{}, error) {
+	if n.set.Empty() {
+		// no type information whatsoever, so this must be an empty slice
+		return reflect.MakeSlice(typeFor(sig.str), 0, 0).Interface(), nil
+	}
+	if !n.set[sig] {
+		return nil, varTypeError{n.String(), sig}
+	}
+	s := reflect.MakeSlice(typeFor(sig.str), len(n.children), len(n.children))
+	for i, v := range n.children {
+		rv, err := v.Value(Signature{sig.str[1:]})
+		if err != nil {
+			return nil, err
+		}
+		s.Index(i).Set(reflect.ValueOf(rv))
+	}
+	return s.Interface(), nil
+}
+
+func varMakeArrayNode(p *varParser, sig Signature) (varNode, error) {
+	var n arrayNode
+	if sig.str != "" {
+		n.set = sigSet{sig: true}
+	}
+	if t := p.next(); t.typ == tokArrayEnd {
+		return n, nil
+	} else {
+		p.backup()
+	}
+Loop:
+	for {
+		t := p.next()
+		switch t.typ {
+		case tokEOF:
+			return nil, io.ErrUnexpectedEOF
+		case tokError:
+			return nil, errors.New(t.val)
+		}
+		p.backup()
+		cn, err := varMakeNode(p)
+		if err != nil {
+			return nil, err
+		}
+		if cset := cn.Sigs(); !cset.Empty() {
+			if n.set.Empty() {
+				n.set = cset.ToArray()
+			} else {
+				nset := cset.ToArray().Intersect(n.set)
+				if nset.Empty() {
+					return nil, fmt.Errorf("can't parse %q with given type information", cn.String())
+				}
+				n.set = nset
+			}
+		}
+		n.children = append(n.children, cn)
+		switch t := p.next(); t.typ {
+		case tokEOF:
+			return nil, io.ErrUnexpectedEOF
+		case tokError:
+			return nil, errors.New(t.val)
+		case tokArrayEnd:
+			break Loop
+		case tokComma:
+			continue
+		default:
+			return nil, fmt.Errorf("unexpected %q", t.val)
+		}
+	}
+	return n, nil
+}
+
+type variantNode struct {
+	n varNode
+}
+
+var variantSet = sigSet{
+	Signature{"v"}: true,
+}
+
+func (variantNode) Infer() (Signature, error) {
+	return Signature{"v"}, nil
+}
+
+func (n variantNode) String() string {
+	return "<" + n.n.String() + ">"
+}
+
+func (variantNode) Sigs() sigSet {
+	return variantSet
+}
+
+func (n variantNode) Value(sig Signature) (interface{}, error) {
+	if sig.str != "v" {
+		return nil, varTypeError{n.String(), sig}
+	}
+	sig, err := varInfer(n.n)
+	if err != nil {
+		return nil, err
+	}
+	v, err := n.n.Value(sig)
+	if err != nil {
+		return nil, err
+	}
+	return MakeVariant(v), nil
+}
+
+func varMakeVariantNode(p *varParser, sig Signature) (varNode, error) {
+	n, err := varMakeNode(p)
+	if err != nil {
+		return nil, err
+	}
+	if t := p.next(); t.typ != tokVariantEnd {
+		return nil, fmt.Errorf("unexpected %q", t.val)
+	}
+	vn := variantNode{n}
+	if sig.str != "" && sig.str != "v" {
+		return nil, varTypeError{vn.String(), sig}
+	}
+	return variantNode{n}, nil
+}
+
+type dictEntry struct {
+	key, val varNode
+}
+
+type dictNode struct {
+	kset, vset sigSet
+	children   []dictEntry
+	val        interface{}
+}
+
+func (n dictNode) Infer() (Signature, error) {
+	for _, v := range n.children {
+		ksig, err := varInfer(v.key)
+		if err != nil {
+			continue
+		}
+		vsig, err := varInfer(v.val)
+		if err != nil {
+			continue
+		}
+		return Signature{"a{" + ksig.str + vsig.str + "}"}, nil
+	}
+	return Signature{}, fmt.Errorf("can't infer type for %q", n.String())
+}
+
+func (n dictNode) String() string {
+	s := "{"
+	for i, v := range n.children {
+		s += v.key.String() + ": " + v.val.String()
+		if i != len(n.children)-1 {
+			s += ", "
+		}
+	}
+	return s + "}"
+}
+
+func (n dictNode) Sigs() sigSet {
+	r := sigSet{}
+	for k := range n.kset {
+		for v := range n.vset {
+			sig := "a{" + k.str + v.str + "}"
+			r[Signature{sig}] = true
+		}
+	}
+	return r
+}
+
+func (n dictNode) Value(sig Signature) (interface{}, error) {
+	set := n.Sigs()
+	if set.Empty() {
+		// no type information -> empty dict
+		return reflect.MakeMap(typeFor(sig.str)).Interface(), nil
+	}
+	if !set[sig] {
+		return nil, varTypeError{n.String(), sig}
+	}
+	m := reflect.MakeMap(typeFor(sig.str))
+	ksig := Signature{sig.str[2:3]}
+	vsig := Signature{sig.str[3 : len(sig.str)-1]}
+	for _, v := range n.children {
+		kv, err := v.key.Value(ksig)
+		if err != nil {
+			return nil, err
+		}
+		vv, err := v.val.Value(vsig)
+		if err != nil {
+			return nil, err
+		}
+		m.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv))
+	}
+	return m.Interface(), nil
+}
+
+func varMakeDictNode(p *varParser, sig Signature) (varNode, error) {
+	var n dictNode
+
+	if sig.str != "" {
+		if len(sig.str) < 5 {
+			return nil, fmt.Errorf("invalid signature %q for dict type", sig)
+		}
+		ksig := Signature{string(sig.str[2])}
+		vsig := Signature{sig.str[3 : len(sig.str)-1]}
+		n.kset = sigSet{ksig: true}
+		n.vset = sigSet{vsig: true}
+	}
+	if t := p.next(); t.typ == tokDictEnd {
+		return n, nil
+	} else {
+		p.backup()
+	}
+Loop:
+	for {
+		t := p.next()
+		switch t.typ {
+		case tokEOF:
+			return nil, io.ErrUnexpectedEOF
+		case tokError:
+			return nil, errors.New(t.val)
+		}
+		p.backup()
+		kn, err := varMakeNode(p)
+		if err != nil {
+			return nil, err
+		}
+		if kset := kn.Sigs(); !kset.Empty() {
+			if n.kset.Empty() {
+				n.kset = kset
+			} else {
+				n.kset = kset.Intersect(n.kset)
+				if n.kset.Empty() {
+					return nil, fmt.Errorf("can't parse %q with given type information", kn.String())
+				}
+			}
+		}
+		t = p.next()
+		switch t.typ {
+		case tokEOF:
+			return nil, io.ErrUnexpectedEOF
+		case tokError:
+			return nil, errors.New(t.val)
+		case tokColon:
+		default:
+			return nil, fmt.Errorf("unexpected %q", t.val)
+		}
+		t = p.next()
+		switch t.typ {
+		case tokEOF:
+			return nil, io.ErrUnexpectedEOF
+		case tokError:
+			return nil, errors.New(t.val)
+		}
+		p.backup()
+		vn, err := varMakeNode(p)
+		if err != nil {
+			return nil, err
+		}
+		if vset := vn.Sigs(); !vset.Empty() {
+			if n.vset.Empty() {
+				n.vset = vset
+			} else {
+				n.vset = n.vset.Intersect(vset)
+				if n.vset.Empty() {
+					return nil, fmt.Errorf("can't parse %q with given type information", vn.String())
+				}
+			}
+		}
+		n.children = append(n.children, dictEntry{kn, vn})
+		t = p.next()
+		switch t.typ {
+		case tokEOF:
+			return nil, io.ErrUnexpectedEOF
+		case tokError:
+			return nil, errors.New(t.val)
+		case tokDictEnd:
+			break Loop
+		case tokComma:
+			continue
+		default:
+			return nil, fmt.Errorf("unexpected %q", t.val)
+		}
+	}
+	return n, nil
+}
+
+type byteStringNode []byte
+
+var byteStringSet = sigSet{
+	Signature{"ay"}: true,
+}
+
+func (byteStringNode) Infer() (Signature, error) {
+	return Signature{"ay"}, nil
+}
+
+func (b byteStringNode) String() string {
+	return string(b)
+}
+
+func (b byteStringNode) Sigs() sigSet {
+	return byteStringSet
+}
+
+func (b byteStringNode) Value(sig Signature) (interface{}, error) {
+	if sig.str != "ay" {
+		return nil, varTypeError{b.String(), sig}
+	}
+	return []byte(b), nil
+}
+
+func varParseByteString(s string) ([]byte, error) {
+	// quotes and b at start are guaranteed to be there
+	b := make([]byte, 0, 1)
+	s = s[2 : len(s)-1]
+	for len(s) != 0 {
+		c := s[0]
+		s = s[1:]
+		if c != '\\' {
+			b = append(b, c)
+			continue
+		}
+		c = s[0]
+		s = s[1:]
+		switch c {
+		case 'a':
+			b = append(b, 0x7)
+		case 'b':
+			b = append(b, 0x8)
+		case 'f':
+			b = append(b, 0xc)
+		case 'n':
+			b = append(b, '\n')
+		case 'r':
+			b = append(b, '\r')
+		case 't':
+			b = append(b, '\t')
+		case 'x':
+			if len(s) < 2 {
+				return nil, errors.New("short escape")
+			}
+			n, err := strconv.ParseUint(s[:2], 16, 8)
+			if err != nil {
+				return nil, err
+			}
+			b = append(b, byte(n))
+			s = s[2:]
+		case '0':
+			if len(s) < 3 {
+				return nil, errors.New("short escape")
+			}
+			n, err := strconv.ParseUint(s[:3], 8, 8)
+			if err != nil {
+				return nil, err
+			}
+			b = append(b, byte(n))
+			s = s[3:]
+		default:
+			b = append(b, c)
+		}
+	}
+	return append(b, 0), nil
+}
+
+func varInfer(n varNode) (Signature, error) {
+	if sig, ok := n.Sigs().Single(); ok {
+		return sig, nil
+	}
+	return n.Infer()
+}