This file is indexed.

/usr/share/pyshared/cobbler/template_api.py is in python-cobbler 2.2.2-0ubuntu33.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
"""
Cobbler provides builtin methods for use in Cheetah templates. $SNIPPET is one
such function and is now used to implement Cobbler's SNIPPET:: syntax.

Written by Daniel Guernsey <danpg102@gmail.com>
Contributions by Michael DeHaan <mdehaan@redhat.com>
US Government work; No explicit copyright attached to this file.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301  USA
"""

import Cheetah.Template
import os.path
import re
import utils
from cexceptions import *

CHEETAH_MACROS_FILE = '/etc/cobbler/cheetah_macros'

# This class is defined using the Cheetah language. Using the 'compile' function
# we can compile the source directly into a python class. This class will allow
# us to define the cheetah builtins.

BuiltinTemplate = Cheetah.Template.Template.compile(source="\n".join([

    # This part (see 'Template' below
    # for the other part) handles the actual inclusion of the file contents. We
    # still need to make the snippet's namespace (searchList) available to the
    # template calling SNIPPET (done in the other part).
    
    # Moved the other functions into /etc/cobbler/cheetah_macros
    # Left SNIPPET here since it is very important.

    # This function can be used in two ways:
    # Cheetah syntax:
    # 
    # $SNIPPET('my_snippet')
    # 
    # SNIPPET syntax:
    # 
    # SNIPPET::my_snippet
    # 
    # This follows all of the rules of snippets and advanced snippets. First it
    # searches for a per-system snippet, then a per-profile snippet, then a
    # general snippet. If none is found, a comment explaining the error is
    # substituted.
    "#def SNIPPET($file)",
        "#set $snippet = $read_snippet($file)",
        "#if $snippet",
            "#include source=$snippet",
        "#else",
            "# Error: no snippet data for $file",
        "#end if",
    "#end def",
]) + "\n")

MacrosTemplate = Cheetah.Template.Template.compile(file=CHEETAH_MACROS_FILE)

class Template(BuiltinTemplate, MacrosTemplate):

    """
    This class will allow us to include any pure python builtin functions.
    It derives from the cheetah-compiled class above. This way, we can include
    both types (cheetah and pure python) of builtins in the same base template.
    We don't need to override __init__
    """
 
    # OK, so this function gets called by Cheetah.Template.Template.__init__ to
    # compile the template into a class. This is probably a kludge, but it
    # add a baseclass argument to the standard compile (see Cheetah's compile
    # docstring) and returns the resulting class. This argument, of course,
    # points to this class. Now any methods entered here (or in the base class
    # above) will be accessible to all cheetah templates compiled by cobbler.


    def compile(klass, *args, **kwargs):
        """
        Compile a cheetah template with cobbler modifications. Modifications
        include SNIPPET:: syntax replacement and inclusion of cobbler builtin
        methods.
        """
        def replacer(match):
            return "$SNIPPET('%s')" % match.group(1)

        def preprocess(source, file):
            # Normally, the cheetah compiler worries about this, but we need to
            # preprocess the actual source
            if source is None:
                if isinstance(file, (str, unicode)):
                    if os.path.exists(file):
                       f = open(file)
                       source = "#errorCatcher Echo\n" + f.read()
                       f.close()
                    else:
                       source = "# Unable to read %s\n" % file
                elif hasattr(file, 'read'):
                    source = file.read()
                file = None # Stop Cheetah from throwing a fit.

             
            rx = re.compile(r'SNIPPET::([A-Za-z0-9_\-\/\.]+)')
            results = rx.sub(replacer, source)
            return (results, file)
        preprocessors = [preprocess]
        if kwargs.has_key('preprocessors'):
            preprocessors.extend(kwargs['preprocessors'])
        kwargs['preprocessors'] = preprocessors
        
        # Instruct Cheetah to use this class as the base for all cheetah templates
        if not kwargs.has_key('baseclass'):
            kwargs['baseclass'] = Template
        
        # Now let Cheetah do the actual compilation
        return Cheetah.Template.Template.compile(*args, **kwargs)
    compile = classmethod(compile)
    
    def read_snippet(self, file):
        """
        Locate the appropriate snippet for the current system and profile and
        read it's contents.

        This file could be located in a remote location.

        This will first check for a per-system snippet, a per-profile snippet,
        a distro snippet, and a general snippet. If no snippet is located, it
        returns None.
        """
        for snipclass in ('system', 'profile', 'distro'):
            if self.varExists('%s_name' % snipclass):
                fullpath = '%s/per_%s/%s/%s' % (self.getVar('snippetsdir'),
                    snipclass, file, self.getVar('%s_name' % snipclass))
                try:
                    contents = utils.read_file_contents(fullpath, fetch_if_remote=True)
                    return contents
                except FileNotFoundException:
                    pass

        try: 
            return "#errorCatcher ListErrors\n" + utils.read_file_contents('%s/%s' % (self.getVar('snippetsdir'), file), fetch_if_remote=True)
        except FileNotFoundException:
            return None

    def SNIPPET(self, file):
        """
        Include the contents of the named snippet here. This is equivalent to
        the #include directive in Cheetah, except that it searches for system
        and profile specific snippets, and it includes the snippet's namespace.

        This may be a little frobby, but it's really cool. This is a pure python
        portion of SNIPPET that appends the snippet's searchList to the caller's
        searchList. This makes any #defs within a given snippet available to the
        template that included the snippet.

        """
        # First, do the actual inclusion. Cheetah (when processing #include)
        # will track the inclusion in self._CHEETAH__cheetahIncludes
        result = BuiltinTemplate.SNIPPET(self, file)

        # Now do our dirty work: locate the new include, and append its
        # searchList to ours.
        # We have to compute the full path again? Eww.

        # This weird method is getting even weirder, the cheetah includes keys
        # are no longer filenames but actual contents of snippets. Regardless
        # this seems to work and hopefully it will be ok.

        snippet_contents = self.read_snippet(file);
        if snippet_contents:
            # Only include what we don't already have. Because Cheetah
            # passes our searchList into included templates, the snippet's
            # searchList will include this templates searchList. We need to
            # avoid duplicating entries.
            childList = self._CHEETAH__cheetahIncludes[snippet_contents].searchList()
            myList = self.searchList()
            for childElem in childList:
                if not childElem in myList:
                    myList.append(childElem)
        
        return result
    
    # This function is used by several cheetah methods in cheetah_macros.
    # It can be used by the end user as well.
    # Ex: Replace all instances of '/etc/banner' with a value stored in
    # $new_banner
    # 
    # sed 's/$sedesc("/etc/banner")/$sedesc($new_banner)/'
    # 
    def sedesc(self, value):
        """
	Escape a string for use in sed.
	"""
        def escchar(c):
            if c in '/^.[]$()|*+?{}\\':
                return '\\' + c
            else:
                return c
        return ''.join([escchar(c) for c in value])