1#!/usr/bin/env python
2"""
3ntlogon.py written by Timothy (rhacer) Grant
4
5Copyright 1999 - 2002 by Timothy Grant
6
7is distributed under the terms of the GNU Public License.
8
9The format for the configuration file is as follows:
10
11While there is some room for confusion, we attempt to process things in
12order of specificity: Global first, Group second, User third, OS Type
13forth. This order can be debated forever, but it seems to make the most
14sense.
15
16# Everything in the Global section applies to all users logging on to the
17# network
18[Global]
19@ECHO "Welcome to our network!!!"
20NET TIME \\\\servername /SET /YES
21NET USE F: \\\\servername\\globalshare /YES
22
23# Map the private user area in the global section so we don't have to
24# create individual user entries for each user!
25NET USE U: \\\\servername\\%U /YES
26
27# Group entries, User entries and OS entries each start with the
28# keyword followed by a dash followed by--appropriately enough the Group
29# name, the User name, or the OS name.
30[Group-admin]
31@ECHO "Welcome administrators!"
32NET USE G: \\\\servername\\adminshare1 /YES
33NET USE I: \\\\servername\\adminshare2 /YES
34
35[Group-peons]
36@ECHO "Be grateful we let you use computers!"
37NET USE G: \\\\servername\\peonshare1 /YES
38
39[Group-hackers]
40@ECHO "What can I do for you today great one?"
41NET USE G: \\\\servername\\hackershare1 /YES
42NET USE I: \\\\servername\\adminshare2 /YES
43
44[User-fred]
45@ECHO "Hello there Fred!"
46NET USE F: \\\\servername\\fredsspecialshare /YES
47
48[OS-WfWg]
49@ECHO "Time to upgrade it?"
50
51# End configuration file
52
53usage: ntlogon [-g | --group=groupname]
54               [-u | --user=username]
55               [-o | --os=osname]
56               [-m | --machine=netbiosname]
57               [-f | --templatefile=filename]
58               [-d | --dir=netlogon directory]
59               [-v | --version]
60               [-h | --help]
61               [--pause]
62               [--debug]
63"""
64#
65#" This quote mark is an artifact of the inability of my editor to
66#  correctly colour code anything after the triple-quoted docstring.
67#  if your editor does not have this flaw, feel free to remove it.
68
69
70import sys
71import getopt
72import re
73import string
74import os
75
76version = "ntlogon.py v0.8"
77
78def buildScript(buf, sections, group, user, ostype, machine, debug, pause):
79    """
80    buildScript() Takes the contents of the template file and builds
81    a DOS batch file to be executed as an NT logon script. It does this
82    by determining which sections of the configuration file should be included
83    and creating a list object that contains each line contained in each
84    included section.  The list object is then returned to the calling
85    routine.
86
87    All comments (#) are removed. A REM is inserted to show
88    which section of the configuration file each line comes from.
89    We leave blanklines as they are sometimes useful for debugging
90
91    We also replace all of the Samba macros (e.g., %U, %G, %a, %m) with their
92    expanded versions which have been passed to us by smbd
93    """
94    hdrstring   = ''
95    script = []
96
97    #
98    # These are the Samba macros that we currently know about.
99    # any user defined macros will also be added to this dictionary.
100    # We do not store the % sign as part of the macro name.
101    # The replace routine will prepend the % sign to all possible
102    # replacements.
103    #
104    macros = {
105        		'U': user,
106                'G': group,
107                'a': ostype,
108                'm': machine
109             }
110
111    #
112    # Process each section defined in the list sections
113    #
114    for s in sections:
115        # print 'searching for: ' + s
116
117        idx = 0
118
119        while idx < len(buf):
120            ln = buf[idx]
121
122            #
123            # We need to set up a regex for each possible section we
124            # know about. This is slightly complicated due to the fact
125            # that section headers contain user defined text.
126            #
127            if s == 'Global':
128                hdrstring = '\[ *' + s + ' *\]'
129            elif s == 'Group':
130                hdrstring = '\[ *' + s + ' *- *' + group + ' *\]'
131            elif s == 'User':
132                hdrstring = '\[ *' + s + ' *- *' + user + ' *\]'
133            elif s == 'OS':
134                hdrstring = '\[ *' + s + ' *- *' + ostype + ' *\]'
135            elif s == 'Machine':
136	        hdrstring = '\[ *' + s + ' *- *' + machine + ' *\]'
137
138            #
139            # See if we have found a section header
140            #
141            if re.search(r'(?i)' + hdrstring, ln):
142                idx = idx + 1   # increment the counter to move to the next
143                                # line.
144
145                x = re.match(r'([^#\r\n]*)', ln)    # Determine the section
146                                                    # name and strip out CR/LF
147                                                    # and comment information
148
149                if debug:
150                    print 'rem ' + x.group(1) + ' commands'
151                else:
152                    # create the rem at the beginning of each section of the
153                    # logon script.
154                    script.append('rem ' + x.group(1) + ' commands')
155
156                #
157                # process each line until we have found another section
158                # header
159                #
160                while not re.search(r'.*\[.*\].*', buf[idx]):
161
162                    #
163                    # strip comments and line endings
164                    #
165                    x = re.match(r'([^#\r\n]*)', buf[idx])
166
167                    if string.strip(x.group(1)) != '' :
168                        # if there is still content  after stripping comments and
169                        # line endings then this is a line to process
170
171                        line = x.group(1)
172
173                        #
174                        # Check to see if this is a macro definition line
175                        #
176                        vardef = re.match(r'(.*)=(.*)', line)
177
178                        if vardef:
179                            varname = string.strip(vardef.group(1))		# Strip leading and
180                            varsub  = string.strip(vardef.group(2))		# and trailing spaces
181
182                            if varname == '':
183                                print "Error: No substition name specified line: %d" % idx
184                                sys.exit(1)
185
186                            if varsub == '':
187                                print "Error: No substitution text provided line: %d" % idx
188                                sys.exit(1)
189
190                            if macros.has_key(varname):
191                                print "Warning: macro %s redefined line: %d" % (varname, idx)
192
193                            macros[varname] = varsub
194                            idx = idx + 1
195                            continue
196
197                        #
198                        # Replace all the  macros that we currently
199                        # know about.
200                        #
201                        # Iterate over the dictionary that contains all known
202                        # macro substitutions.
203                        #
204                        # We test for a macro name by prepending % to each dictionary
205                        # key.
206                        #
207                        for varname in macros.keys():
208                            line = re.sub(r'%' + varname + r'(\W)',
209                                          macros[varname] + r'\1', line)
210
211                        if debug:
212                            print line
213                            if pause:
214                                print 'pause'
215                        else:
216                            script.append(line)
217
218                    idx = idx + 1
219
220                    if idx == len(buf):
221                        break   # if we have reached the end of the file
222                                # stop processing.
223
224            idx = idx + 1   # increment the line counter
225
226        if debug:
227            print ''
228        else:
229            script.append('')
230
231    return script
232
233# End buildScript()
234
235def run():
236    """
237    run() everything starts here. The main routine reads the command line
238    arguments, opens and reads the configuration file.
239    """
240    configfile  = '/etc/ntlogon.conf'   # Default configuration file
241    group       = ''                    # Default group
242    user        = ''                    # Default user
243    ostype      = ''                    # Default os
244    machine     = ''			# Default machine type
245    outfile     = 'logon.bat'           # Default batch file name
246                                        #   this file name WILL take on the form
247                                        #   username.bat if a username is specified
248    debug       = 0                     # Default debugging mode
249    pause		= 0						# Default pause mode
250    outdir      = '/usr/local/samba/netlogon/'   # Default netlogon directory
251
252    sections    = ['Global', 'Machine', 'OS', 'Group', 'User'] # Currently supported
253                                                    # configuration file
254                                                    # sections
255
256    options, args = getopt.getopt(sys.argv[1:], 'd:f:g:ho:u:m:v',
257                                 ['templatefile=',
258                                  'group=',
259                                  'help',
260                                  'os=',
261                                  'user=',
262                                  'machine=',
263                                  'dir=',
264                                  'version',
265                                  'pause',
266                                  'debug'])
267
268    #
269    # Process the command line arguments
270    #
271    for i in options:
272        # template file to process
273        if (i[0] == '-f') or (i[0] == '--templatefile'):
274            configfile = i[1]
275            # print 'configfile = ' + configfile
276
277        # define the group to be used
278        elif (i[0] == '-g') or (i[0] == '--group'):
279            group = i[1]
280            # print 'group = ' + group
281
282        # define the os type
283        elif (i[0] == '-o') or (i[0] == '--os'):
284            ostype = i[1]
285            # print 'os = ' + os
286
287        # define the user
288        elif (i[0] == '-u') or (i[0] == '--user'):
289            user = i[1]
290            outfile = user + '.bat' # Setup the output file name
291            # print 'user = ' + user
292
293        # define the machine
294        elif (i[0] == '-m') or (i[0] == '--machine'):
295            machine = i[1]
296
297        # define the netlogon directory
298        elif (i[0] == '-d') or (i[0] == '--dir'):
299            outdir = i[1]
300            # print 'outdir = ' + outdir
301
302        # if we are asked to turn on debug info, do so.
303        elif (i[0] == '--debug'):
304            debug = 1
305            # print 'debug = ' + debug
306
307        # if we are asked to turn on the automatic pause functionality, do so
308        elif (i[0] == '--pause'):
309            pause = 1
310            # print 'pause = ' + pause
311
312        # if we are asked for the version number, print it.
313        elif (i[0] == '-v') or (i[0] == '--version'):
314            print version
315            sys.exit(0)
316
317        # if we are asked for help print the docstring.
318        elif (i[0] == '-h') or (i[0] == '--help'):
319            print __doc__
320            sys.exit(0)
321
322    #
323    # open the configuration file
324    #
325    try:
326        iFile = open(configfile, 'r')
327    except IOError:
328        print 'Unable to open configuration file: ' + configfile
329        sys.exit(1)
330
331
332    #
333    # open the output file
334    #
335    if not debug:
336        try:
337            oFile = open(outdir + outfile, 'w')
338        except IOError:
339            print 'Unable to open logon script file: ' + outdir + outfile
340            sys.exit(1)
341
342    buf = iFile.readlines() # read in the entire configuration file
343
344    #
345    # call the script building routine
346    #
347    script = buildScript(buf, sections, group, user, ostype, machine, debug, pause)
348
349    #
350    # write out the script file
351    #
352    if not debug:
353        for ln in script:
354            oFile.write(ln + '\r\n')
355            if pause:
356                if string.strip(ln) != '':			# Because whitespace
357                    oFile.write('pause' + '\r\n')	# is a useful tool, we
358                    								# don't put pauses after
359                                                    # an empty line.
360
361
362# End run()
363
364#
365# immediate-mode commands, for drag-and-drop or execfile() execution
366#
367if __name__ == '__main__':
368    run()
369else:
370    print "Module ntlogon.py imported."
371    print "To run, type: ntlogon.run()"
372    print "To reload after changes to the source, type: reload(ntlogon)"
373
374#
375# End NTLogon.py
376#
377