source: trunk/packages/xen-3.1/xen-3.1/tools/python/xen/xm/cfgbootpolicy.py @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 7.0 KB
Line 
1#============================================================================
2# This library is free software; you can redistribute it and/or
3# modify it under the terms of version 2.1 of the GNU Lesser General Public
4# License as published by the Free Software Foundation.
5#
6# This library is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9# Lesser General Public License for more details.
10#
11# You should have received a copy of the GNU Lesser General Public
12# License along with this library; if not, write to the Free Software
13# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14#============================================================================
15# Copyright (C) 2006 International Business Machines Corp.
16# Author: Reiner Sailer <sailer@us.ibm.com>
17# Contributions: Stefan Berger <stefanb@us.ibm.com>
18#============================================================================
19"""Configuring a security policy into the boot configuration
20"""
21
22import sys
23import traceback
24import tempfile
25import os, stat
26import shutil
27import string
28import re
29from xen.util.security import err
30from xen.util.security import policy_dir_prefix, xen_title_re
31from xen.util.security import boot_filename, altboot_filename
32from xen.util.security import any_title_re, xen_kernel_re, any_module_re
33from xen.util.security import empty_line_re, binary_name_re, policy_name_re
34from xen.xm.opts import OptionError
35
36def help():
37    return """
38    Adds a 'module' line to the Xen grub configuration file entry
39    so that Xen boots with a specific access control policy. If
40    boot-title is not given, then this script tries to determine
41    it by looking for a title starting with \"XEN\". If there are
42    multiple entries matching, then it must be called with the unique
43    beginning of the title's name.\n"""
44
45def strip_title(line):
46    """
47    strips whitespace left and right and cuts 'title'
48    """
49    s_title = string.strip(line)
50    pos = string.index(s_title, "title")
51    if pos >= 0:
52        return s_title[pos+6:]
53    else:
54        return s_title
55
56
57def insert_policy(boot_file, alt_boot_file, user_title, policy_name):
58    """
59    inserts policy binary file as last line of the grub entry
60    matching the user_title or default title
61    """
62    if user_title:
63        #replace "(" by "\(" and ")" by "\)" for matching
64        user_title = string.replace(user_title, "(", "\(")
65        user_title = string.replace(user_title, ")", "\)")
66        user_title_re = re.compile("\s*title\s+.*%s" \
67                                   % user_title, re.IGNORECASE)
68    else:
69        user_title_re = xen_title_re
70
71    within_xen_title = 0
72    within_xen_entry = 0
73    insert_at_end_of_entry = 0
74    path_prefix = ''
75    this_title = ''
76    extended_titles = []
77    (tmp_fd, tmp_grub) = tempfile.mkstemp()
78    #First check whether menu.lst exists
79    if not os.path.isfile(boot_file):
80        #take alternate boot file (grub.conf) instead
81        boot_file = alt_boot_file
82    #follow symlink since menue.lst might be linked to grub.conf
83    if stat.S_ISLNK(os.lstat(boot_file)[stat.ST_MODE]):
84        new_name = os.readlink(boot_file)
85        if new_name[0] == "/":
86            boot_file = new_name
87        else:
88            path = boot_file.split('/')
89            path[len(path)-1] = new_name
90            boot_file = '/'.join(path)
91        if not os.path.exists(boot_file):
92            err("Boot file \'%s\' not found." % boot_file)
93    grub_fd = open(boot_file)
94    for line in grub_fd:
95        if user_title_re.match(line):
96            this_title = strip_title(line)
97            within_xen_title = 1
98        elif within_xen_title and xen_kernel_re.match(line):
99            insert_at_end_of_entry = 1
100            #use prefix from xen.gz path for policy
101            path_prefix = line.split()[1]
102            idx = path_prefix.rfind('/')
103            if idx >= 0:
104                path_prefix = path_prefix[0:idx+1]
105            else:
106                path_prefix = ''
107        elif any_module_re.match(line) and insert_at_end_of_entry:
108            if binary_name_re.match(line):
109                #delete existing policy module line
110                line=''
111        elif any_title_re.match(line):
112            within_xen_title = 0
113
114        if (empty_line_re.match(line) or any_title_re.match(line)) and \
115            insert_at_end_of_entry:
116            #newline or new title: we insert the policy module line here
117            os.write(tmp_fd, "\tmodule " + path_prefix + policy_name + ".bin\n")
118            extended_titles.append(this_title)
119            insert_at_end_of_entry = 0
120        #write the line that was read (except potential existing policy entry)
121        os.write(tmp_fd, line)
122
123    if insert_at_end_of_entry:
124        #last entry, no empty line at end of file
125        os.write(tmp_fd, "\tmodule " + path_prefix + policy_name + ".bin\n")
126        extended_titles.append(this_title)
127
128    #if more than one entry was changed, abort
129    if len(extended_titles) > 1:
130        err("Following boot entries matched: %s. \nPlease specify "
131            "unique part of the boot title." % extended_titles)
132    if len(extended_titles) == 0:
133        err("Boot entry not found. Please specify unique part "
134            "of the boot title.")
135
136    #temp file might be destroyed when closing it, first copy it
137    shutil.move(boot_file, boot_file+"_save")
138    shutil.copyfile(tmp_grub, boot_file)
139    os.close(tmp_fd)
140    #sometimes the temp file does not disappear
141    try:
142        os.remove(tmp_grub)
143    except:
144        pass
145    return extended_titles[0]
146
147
148def main(argv):
149    user_kver = None
150    user_title = None
151    if len(argv) == 2:
152        policy = argv[1]
153    elif len(argv) == 3:
154        policy = argv[1]
155        user_title = argv[2]
156    else:
157        raise OptionError('Invalid number of arguments')
158   
159    if not policy_name_re.match(policy):
160        raise OptionError("Illegal policy name: '%s'" % policy)
161
162    policy_file = '/'.join([policy_dir_prefix] + policy.split('.'))
163    src_binary_policy_file = policy_file + ".bin"
164    #check if .bin exists or if policy file exists
165    if not os.path.isfile(src_binary_policy_file):
166        if not os.path.isfile(policy_file + "-security_policy.xml"):
167            raise OptionError("Unknown policy '%s'" % policy)
168        else:
169            err_msg = "Cannot find binary file for policy '%s'." % policy
170            err_msg += " Please use makepolicy to create binary file."
171            raise OptionError(err_msg)
172   
173    dst_binary_policy_file = "/boot/" + policy + ".bin"
174    shutil.copyfile(src_binary_policy_file, dst_binary_policy_file)
175   
176    entryname = insert_policy(boot_filename, altboot_filename,
177                              user_title, policy)
178    print "Boot entry '%s' extended and \'%s\' copied to /boot" \
179          % (entryname, policy + ".bin")
180
181if __name__ == '__main__':
182    try:
183        main(sys.argv)
184    except Exception, e:
185        sys.stderr.write('Error: ' + str(e) + '\n')   
186        sys.exit(-1)
Note: See TracBrowser for help on using the repository browser.