Extend 'xm dumppolicy' to support Xen-API
authorKeir Fraser <keir@xensource.com>
Wed, 3 Oct 2007 13:04:51 +0000 (14:04 +0100)
committerKeir Fraser <keir@xensource.com>
Wed, 3 Oct 2007 13:04:51 +0000 (14:04 +0100)
I am extending 'xm dumppolicy' to be used via the Xen-API. For this
there are two new functions in the ACM policy class:
 - get the currently enforced policy including statistical data from
   the hypervisor
- get the ACM 'ssidref' of a Domain. Since this may be a ACM-specific
  variable or type (int) I put it into the ACM class.

I extended the Xen-API documentation with the two new functions.

Signed-off-by: Stefan Berger <Stefanb@us.ibm.com>
docs/xen-api/xenapi-datamodel.tex
tools/libxen/include/xen/api/xen_acmpolicy.h
tools/libxen/src/xen_acmpolicy.c
tools/python/xen/lowlevel/acm/acm.c
tools/python/xen/util/acmpolicy.py
tools/python/xen/util/xsm/acm/acm.py
tools/python/xen/xend/XendXSPolicy.py
tools/python/xen/xend/XendXSPolicyAdmin.py
tools/python/xen/xm/dumppolicy.py
tools/security/secpol_tool.c

index 8562d6e5b3c45b69c0fb22d624d9ea69f4c3fb39..897fe298872c6e0aa1e54ba28d3127aaeab8cf7c 100644 (file)
@@ -15057,7 +15057,7 @@ Mapping information of the referenced policy.
 Get the binary policy representation of the referenced policy.
 
  \noindent {\bf Signature:}
-\begin{verbatim} string get_map (session_id s, xs ref self)\end{verbatim}
+\begin{verbatim} string get_binary (session_id s, xs ref self)\end{verbatim}
 
 
 \noindent{\bf Arguments:}
@@ -15080,6 +15080,78 @@ string
 
 
 Base64-encoded representation of the binary policy.
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_enforced\_binary}
+
+{\bf Overview:}
+Get the binary policy representation of the currently enforced ACM policy.
+In case the default policy is loaded in the hypervisor, a policy may be
+managed by xend that is not yet loaded into the hypervisor.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_enforced_binary (session_id s, xs ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt xs ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+Base64-encoded representation of the binary policy.
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VM\_ssidref}
+
+{\bf Overview:}
+Get the ACM ssidref of the given virtual machine.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_VM_ssidref (session_id s, vm ref vm)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt vm ref } & vm & reference to a valid VM \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+The ssidref of the given virtual machine.
+
+\vspace{0.3cm}
+
+\noindent{\bf Possible Error Codes:}
+  {\tt HANDLE\_INVALID, VM\_BAD\_POWER\_STATE, SECURITY\_ERROR}
+
 \vspace{0.3cm}
 \vspace{0.3cm}
 \vspace{0.3cm}
index 4ac1cfd8e85f0786790e74c33780942b51a3009a..d0b4a500ca698cce70ab47d572c9d8b1f210825a 100644 (file)
@@ -108,7 +108,22 @@ xen_acmpolicy_get_binary(xen_session *session, char **binary,
                          xen_xspolicy xspolicy);
 
 /**
- * Get the UUID filed of the given policy.
+ * Get the binary representation (base64-encoded) of the currently
+ * enforced policy.
+ */
+extern bool
+xen_acmpolicy_get_enforced_binary(xen_session *session, char **binary,
+                                  xen_xspolicy xspolicy);
+
+/**
+ * Get the ACM ssidref of the given VM.
+ */
+bool
+xen_acmpolicy_get_VM_ssidref(xen_session *session, int64_t *result,
+                             xen_vm vm);
+
+/**
+ * Get the UUID field of the given policy.
  */
 bool
 xen_acmpolicy_get_uuid(xen_session *session, char **result,
index 1a6190bfeec7cec79edb86066fce41bd3c95ea9b..f8d69195a4673320d1c4294f0d3a6e6072f9ab6f 100644 (file)
@@ -216,6 +216,41 @@ xen_acmpolicy_get_binary(xen_session *session, char **result,
 }
 
 
+bool
+xen_acmpolicy_get_enforced_binary(xen_session *session, char **result,
+                                  xen_xspolicy xspolicy)
+{
+    abstract_value param_values[] =
+        {
+            { .type = &abstract_type_string,
+              .u.string_val = xspolicy },
+        };
+
+    abstract_type result_type = abstract_type_string;
+
+    *result = NULL;
+    XEN_CALL_("ACMPolicy.get_enforced_binary");
+    return session->ok;
+}
+
+
+bool
+xen_acmpolicy_get_VM_ssidref(xen_session *session,
+                             int64_t *result, xen_vm vm)
+{
+    abstract_value param_values[] =
+        {
+            { .type = &abstract_type_string,
+              .u.string_val = vm }
+        };
+
+    abstract_type result_type = abstract_type_int;
+
+    XEN_CALL_("ACMPolicy.get_VM_ssidref");
+    return session->ok;
+}
+
+
 bool
 xen_acmpolicy_get_uuid(xen_session *session, char **result,
                        xen_xspolicy xspolicy)
index 0a37ba3d9245a4b7d58603fa1b1e266edd9fd54a..1daa4e626a2adb6c9d69c4a7b55c53423ce9a97b 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <stdlib.h>
+#include <arpa/inet.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
 #include <xen/xsm/acm.h>
@@ -258,6 +259,41 @@ static PyObject *chgpolicy(PyObject *self, PyObject *args)
 }
 
 
+static PyObject *getpolicy(PyObject *self, PyObject *args)
+{
+    struct acm_getpolicy getpolicy;
+    int xc_handle, rc;
+    uint8_t pull_buffer[8192];
+    PyObject *result;
+    uint32_t len = sizeof(pull_buffer);
+
+    memset(&getpolicy, 0x0, sizeof(getpolicy));
+    set_xen_guest_handle(getpolicy.pullcache, pull_buffer);
+    getpolicy.pullcache_size = sizeof(pull_buffer);
+
+    if ((xc_handle = xc_interface_open()) <= 0) {
+        PyErr_SetString(PyExc_IOError, ctrlif_op);
+        return NULL;
+    }
+
+    rc = xc_acm_op(xc_handle, ACMOP_getpolicy, &getpolicy, sizeof(getpolicy));
+
+    xc_interface_close(xc_handle);
+
+    if (rc == 0) {
+        struct acm_policy_buffer *header =
+                       (struct acm_policy_buffer *)pull_buffer;
+        if (ntohl(header->len) < sizeof(pull_buffer))
+            len = ntohl(header->len);
+    } else {
+        len = 0;
+    }
+
+    result = Py_BuildValue("is#", rc, pull_buffer, len);
+    return result;
+}
+
+
 static PyObject *relabel_domains(PyObject *self, PyObject *args)
 {
     struct acm_relabel_doms reldoms;
@@ -313,6 +349,7 @@ static PyMethodDef acmMethods[] = {
     {"getssid",     getssid,     METH_VARARGS, "Retrieve label information and ssidref for a domain"},
     {"getdecision", getdecision, METH_VARARGS, "Retrieve ACM access control decision"},
     {"chgpolicy",   chgpolicy,   METH_VARARGS, "Change the policy in one step"},
+    {"getpolicy",   getpolicy,   METH_NOARGS , "Get the binary policy from the hypervisor"},
     {"relabel_domains", relabel_domains, METH_VARARGS, "Relabel domains"},
     /* end of list (extend list above this line) */
     {NULL, NULL, 0, NULL}
index 36aa88cbd3e4a3630e988183c766c5d0046ab130..d11b40dec0955c94805b81d675dbe90a1005c465 100644 (file)
@@ -1264,3 +1264,11 @@ class ACMPolicy(XSPolicy):
             log.info("The following Ch. Wall types in labels were unknown:" \
                      " %s" % list(unknown_chw))
         return rc, mapfile, all_bin.tostring()
+
+    def get_enforced_binary(self):
+        rc, binpol = security.hv_get_policy()
+        if rc != 0:
+            raise SecurityError(-xsconstants.XSERR_HV_OP_FAILED)
+        return binpol
+
+    get_enforced_binary = classmethod(get_enforced_binary)
index d58652e06c03a50ba2188737cbdc4404c9638691..53081f0261506fc8890e675c209e956db08b0650 100644 (file)
@@ -507,6 +507,22 @@ def hv_chg_policy(bin_pol, del_array, chg_array):
         rc = -xsconstants.XSERR_HV_OP_FAILED
     return rc, errors
 
+def hv_get_policy():
+    """
+        Gte the binary policy enforced in the hypervisor
+    """
+    rc = -xsconstants.XSERR_GENERAL_FAILURE
+    bin_pol = ""
+    if not on():
+        err("No policy active.")
+    try:
+        rc, bin_pol = acm.getpolicy()
+    except Exception, e:
+        pass
+    if len(bin_pol) == 0:
+        bin_pol = None
+    return rc, bin_pol
+
 
 def make_policy(policy_name):
     policy_file = string.join(string.split(policy_name, "."), "/")
@@ -546,10 +562,22 @@ def dump_policy():
 
     (ret, output) = commands.getstatusoutput(xensec_tool + " getpolicy")
     if ret:
-       err("Dumping hypervisor policy failed:\n" + output)
+        err("Dumping hypervisor policy failed:\n" + output)
+
     print output
 
 
+def dump_policy_file(filename, ssidref=None):
+    ssid = ""
+    if ssidref:
+        ssid = " " + str(ssidref)
+    (ret, output) = commands.getstatusoutput(xensec_tool + " dumppolicy " +
+                                             filename + ssid)
+    if ret:
+        err("Dumping policy failed:\n" + output)
+
+    print output
+
 
 def list_labels(policy_name, condition):
     if (not policy_name) and (active_policy) in ["NULL", "INACTIVE", "DEFAULT"]:
index de30fd7caae9e217ce619d7a22639e889bdb1b2a..11c1a1b63fd22bccded3da61ccb4b01bfae5f7d1 100644 (file)
 # Copyright (c) 2006 Xensource
 #============================================================================
 
+import base64
 import logging
+from xen.xend import XendDomain
 from xen.xend.XendBase import XendBase
 from xen.xend.XendError import *
+from xen.xend.XendAPIConstants import *
 from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
 from xen.util import xsconstants
 import xen.util.xsm.xsm as security
-import base64
 
 log = logging.getLogger("xend.XendXSPolicy")
 log.setLevel(logging.TRACE)
@@ -184,8 +186,13 @@ class XendACMPolicy(XendXSPolicy):
                    'header' ]
         return XendXSPolicy.getAttrRO() + attrRO
 
+    def getFuncs(self):
+        funcs = [ 'get_enforced_binary', 'get_VM_ssidref' ]
+        return XendBase.getFuncs() + funcs
+
     getClass    = classmethod(getClass)
     getAttrRO   = classmethod(getAttrRO)
+    getFuncs    = classmethod(getFuncs)
 
     def __init__(self, acmpol, record, uuid):
         """ acmpol = actual ACMPolicy object """
@@ -221,3 +228,25 @@ class XendACMPolicy(XendXSPolicy):
     def get_binary(self):
         polbin = self.acmpol.get_bin()
         return base64.b64encode(polbin)
+
+    def get_VM_ssidref(self, vm_ref):
+        dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+        if not dom:
+            raise InvalidHandleError("VM", vm_ref)
+        if dom._stateGet() not in [ XEN_API_VM_POWER_STATE_RUNNING, \
+                                    XEN_API_VM_POWER_STATE_PAUSED ]:
+            raise VMBadState("Domain is not running or paused.")
+        ssid = security.get_ssid(dom.getDomid())
+        if not ssid:
+            raise SecurityError(-xsconstants.XSERR_GENERAL_FAILURE)
+        return ssid[3]
+
+    def get_enforced_binary(self):
+        polbin = XSPolicyAdminInstance(). \
+                   get_enforced_binary(xsconstants.XS_POLICY_ACM)
+        if polbin:
+            return base64.b64encode(polbin)
+        return None
+
+    get_enforced_binary = classmethod(get_enforced_binary)
+    get_VM_ssidref = classmethod(get_VM_ssidref)
index c97e085dd0bef98717ef87eb62fe440be0894708..c8f70b9242a3afb39ceb75b8aad9f2a4121fde81 100644 (file)
@@ -324,6 +324,11 @@ class XSPolicyAdmin:
             stes = loadedpol.policy_get_stes_of_vmlabel(tmp[2])
         return stes
 
+    def get_enforced_binary(self, xstype):
+        res = None
+        if xstype == xsconstants.XS_POLICY_ACM:
+            res = ACMPolicy.get_enforced_binary()
+        return res
 
 poladmin = None
 
index 77c4151beb9650cee98f799ff733f3b5bc98d513..7bd2ba15ded7cca3b0ac078f9a9d9502caf0947c 100644 (file)
 #============================================================================
 """Display currently enforced policy (low-level hypervisor representation).
 """
+import os
 import sys
-from xen.util.xsm.xsm import XSMError, err, dump_policy
+import base64
+import tempfile
+import commands
+from xen.util.xsm.xsm import XSMError, err, dump_policy, dump_policy_file
 from xen.xm.opts import OptionError
+from xen.xm import main as xm_main
+from xen.xm.main import server
+from xen.util import xsconstants
+
+DOM0_UUID = "00000000-0000-0000-0000-000000000000"
 
 def help():
     return """
@@ -30,7 +39,25 @@ def main(argv):
     if len(argv) != 1:
         raise OptionError("No arguments expected.")
 
-    dump_policy()
+    if xm_main.serverType == xm_main.SERVER_XEN_API:
+        try:
+            bin_pol = server.xenapi.ACMPolicy.get_enforced_binary()
+            if bin_pol:
+                dom0_ssid = server.xenapi.ACMPolicy.get_VM_ssidref(DOM0_UUID)
+                bin = base64.b64decode(bin_pol)
+                try:
+                    fd, filename = tempfile.mkstemp(suffix=".bin")
+                    os.write(fd, bin)
+                    os.close(fd)
+                    dump_policy_file(filename, dom0_ssid)
+                finally:
+                    os.unlink(filename)
+            else:
+                err("No policy is installed.")
+        except Exception, e:
+            err("An error occurred getting the running policy: %s" % str(e))
+    else:
+        dump_policy()
 
 if __name__ == '__main__':
     try:
index 14b4bcc73da9409642be71aaff43cc0cca43cd99..e9da8e4827b65faffa8dfa99d4a9ae3556023042 100644 (file)
@@ -49,7 +49,9 @@ void usage(char *progname)
            "ACTION is one of:\n"
            "\t getpolicy\n"
            "\t dumpstats\n"
-           "\t loadpolicy <binary policy file>\n", progname);
+           "\t loadpolicy <binary policy file>\n"
+           "\t dumppolicy <binary policy file> [Dom-0 ssidref]\n",
+           progname);
     exit(-1);
 }
 
@@ -288,53 +290,93 @@ int acm_domain_getpolicy(int xc_handle)
     return ret;
 }
 
-/************************ load binary policy ******************************/
+/************************ dump binary policy ******************************/
 
-int acm_domain_loadpolicy(int xc_handle, const char *filename)
+static int load_file(const char *filename,
+                     uint8_t **buffer, off_t *len)
 {
     struct stat mystat;
-    int ret, fd;
-    off_t len;
-    uint8_t *buffer;
-    uint16_t chwall_ssidref, ste_ssidref;
+    int ret = 0;
+    int fd;
 
-    if ((ret = stat(filename, &mystat))) {
+    if ((ret = stat(filename, &mystat)) != 0) {
         printf("File %s not found.\n", filename);
+        ret = errno;
         goto out;
     }
 
-    len = mystat.st_size;
-    if ((buffer = malloc(len)) == NULL) {
+    *len = mystat.st_size;
+
+    if ((*buffer = malloc(*len)) == NULL) {
         ret = -ENOMEM;
         goto out;
     }
+
     if ((fd = open(filename, O_RDONLY)) <= 0) {
         ret = -ENOENT;
         printf("File %s not found.\n", filename);
         goto free_out;
     }
-    ret =acm_get_ssidref(xc_handle, 0, &chwall_ssidref, &ste_ssidref);
-    if (ret < 0) {
-        goto free_out;
-    }
-    if (len == read(fd, buffer, len)) {
-        struct acm_setpolicy setpolicy;
-        /* dump it and then push it down into xen/acm */
+
+    if (*len == read(fd, *buffer, *len))
+        return 0;
+
+free_out:
+    free(*buffer);
+    *buffer = NULL;
+    *len = 0;
+out:
+    return ret;
+}
+
+static int acm_domain_dumppolicy(const char *filename, uint32_t ssidref)
+{
+    uint8_t *buffer = NULL;
+    off_t len;
+    int ret = 0;
+    uint16_t chwall_ssidref, ste_ssidref;
+
+    chwall_ssidref = (ssidref      ) & 0xffff;
+    ste_ssidref    = (ssidref >> 16) & 0xffff;
+
+    if ((ret = load_file(filename, &buffer, &len)) == 0) {
         acm_dump_policy_buffer(buffer, len, chwall_ssidref, ste_ssidref);
-        set_xen_guest_handle(setpolicy.pushcache, buffer);
-        setpolicy.pushcache_size = len;
-        ret = xc_acm_op(xc_handle, ACMOP_setpolicy, &setpolicy, sizeof(setpolicy));
+        free(buffer);
+    }
 
-        if (ret)
-            printf
-                ("ERROR setting policy.\n");
-        else
-            printf("Successfully changed policy.\n");
+    return ret;
+}
+
+/************************ load binary policy ******************************/
 
+int acm_domain_loadpolicy(int xc_handle, const char *filename)
+{
+    int ret;
+    off_t len;
+    uint8_t *buffer;
+    uint16_t chwall_ssidref, ste_ssidref;
+    struct acm_setpolicy setpolicy;
+
+    ret = load_file(filename, &buffer, &len);
+    if (ret != 0)
+        goto out;
+
+    ret = acm_get_ssidref(xc_handle, 0, &chwall_ssidref, &ste_ssidref);
+    if (ret < 0)
+        goto free_out;
+
+    /* dump it and then push it down into xen/acm */
+    acm_dump_policy_buffer(buffer, len, chwall_ssidref, ste_ssidref);
+    set_xen_guest_handle(setpolicy.pushcache, buffer);
+    setpolicy.pushcache_size = len;
+    ret = xc_acm_op(xc_handle, ACMOP_setpolicy, &setpolicy, sizeof(setpolicy));
+
+    if (ret) {
+        printf("ERROR setting policy.\n");
     } else {
-        ret = -1;
+        printf("Successfully changed policy.\n");
     }
-    close(fd);
+
   free_out:
     free(buffer);
   out:
@@ -435,26 +477,56 @@ int main(int argc, char **argv)
     if (argc < 2)
         usage(argv[0]);
 
-    if ((xc_handle = xc_interface_open()) <= 0) {
-        printf("ERROR: Could not open xen privcmd device!\n");
-        exit(-1);
-    }
 
     if (!strcmp(argv[1], "getpolicy")) {
         if (argc != 2)
             usage(argv[0]);
+
+        if ((xc_handle = xc_interface_open()) <= 0) {
+            printf("ERROR: Could not open xen privcmd device!\n");
+            exit(-1);
+        }
+
         ret = acm_domain_getpolicy(xc_handle);
+
+        xc_interface_close(xc_handle);
     } else if (!strcmp(argv[1], "loadpolicy")) {
         if (argc != 3)
             usage(argv[0]);
+
+        if ((xc_handle = xc_interface_open()) <= 0) {
+            printf("ERROR: Could not open xen privcmd device!\n");
+            exit(-1);
+        }
+
         ret = acm_domain_loadpolicy(xc_handle, argv[2]);
+
+        xc_interface_close(xc_handle);
     } else if (!strcmp(argv[1], "dumpstats")) {
         if (argc != 2)
             usage(argv[0]);
+
+        if ((xc_handle = xc_interface_open()) <= 0) {
+            printf("ERROR: Could not open xen privcmd device!\n");
+            exit(-1);
+        }
+
         ret = acm_domain_dumpstats(xc_handle);
+
+        xc_interface_close(xc_handle);
+    } else if (!strcmp(argv[1], "dumppolicy")) {
+        uint32_t ssidref = 0xffffffff;
+        if (argc < 3 || argc > 4)
+            usage(argv[0]);
+        if (argc == 4) {
+            if (!sscanf(argv[3], "%i", &ssidref)) {
+                printf("Error: Could not parse ssidref.\n");
+                exit(-1);
+            }
+        }
+        ret = acm_domain_dumppolicy(argv[2], ssidref);
     } else
         usage(argv[0]);
 
-    xc_interface_close(xc_handle);
     return ret;
 }