1 | #!/usr/bin/env python
|
---|
2 | """
|
---|
3 | ntlogon.py written by Timothy (rhacer) Grant
|
---|
4 |
|
---|
5 | Copyright 1999 - 2002 by Timothy Grant
|
---|
6 |
|
---|
7 | is distributed under the terms of the GNU Public License.
|
---|
8 |
|
---|
9 | The format for the configuration file is as follows:
|
---|
10 |
|
---|
11 | While there is some room for confusion, we attempt to process things in
|
---|
12 | order of specificity: Global first, Group second, User third, OS Type
|
---|
13 | forth. This order can be debated forever, but it seems to make the most
|
---|
14 | sense.
|
---|
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!!!"
|
---|
20 | NET TIME \\\\servername /SET /YES
|
---|
21 | NET 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!
|
---|
25 | NET 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!"
|
---|
32 | NET USE G: \\\\servername\\adminshare1 /YES
|
---|
33 | NET USE I: \\\\servername\\adminshare2 /YES
|
---|
34 |
|
---|
35 | [Group-peons]
|
---|
36 | @ECHO "Be grateful we let you use computers!"
|
---|
37 | NET USE G: \\\\servername\\peonshare1 /YES
|
---|
38 |
|
---|
39 | [Group-hackers]
|
---|
40 | @ECHO "What can I do for you today great one?"
|
---|
41 | NET USE G: \\\\servername\\hackershare1 /YES
|
---|
42 | NET USE I: \\\\servername\\adminshare2 /YES
|
---|
43 |
|
---|
44 | [User-fred]
|
---|
45 | @ECHO "Hello there Fred!"
|
---|
46 | NET USE F: \\\\servername\\fredsspecialshare /YES
|
---|
47 |
|
---|
48 | [OS-WfWg]
|
---|
49 | @ECHO "Time to upgrade it?"
|
---|
50 |
|
---|
51 | # End configuration file
|
---|
52 |
|
---|
53 | usage: 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 |
|
---|
70 | import sys
|
---|
71 | import getopt
|
---|
72 | import re
|
---|
73 | import string
|
---|
74 | import os
|
---|
75 |
|
---|
76 | version = "ntlogon.py v0.8"
|
---|
77 |
|
---|
78 | def 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 |
|
---|
235 | def 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 | #
|
---|
367 | if __name__ == '__main__':
|
---|
368 | run()
|
---|
369 | else:
|
---|
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 | #
|
---|