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