summaryrefslogtreecommitdiffstats
path: root/examples/ntlogon/ntlogon.py
blob: ba46ba8ffcfe88f94a5172120cb9a2b6440deb49 (plain)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
#!/usr/bin/env python
"""
ntlogon.py written by Timothy (rhacer) Grant

Copyright 1999 - 2002 by Timothy Grant 

is distributed under the terms of the GNU Public License.

The format for the configuration file is as follows:

While there is some room for confusion, we attempt to process things in
order of specificity: Global first, Group second, User third, OS Type
forth. This order can be debated forever, but it seems to make the most
sense.

# Everything in the Global section applies to all users logging on to the
# network
[Global]
@ECHO "Welcome to our network!!!"
NET TIME \\\\servername /SET /YES
NET USE F: \\\\servername\\globalshare /YES

# Map the private user area in the global section so we don't have to
# create individual user entries for each user!
NET USE U: \\\\servername\\%U /YES

# Group entries, User entries and OS entries each start with the
# keyword followed by a dash followed by--appropriately enough the Group
# name, the User name, or the OS name.
[Group-admin]
@ECHO "Welcome administrators!"
NET USE G: \\\\servername\\adminshare1 /YES
NET USE I: \\\\servername\\adminshare2 /YES

[Group-peons]
@ECHO "Be grateful we let you use computers!"
NET USE G: \\\\servername\\peonshare1 /YES

[Group-hackers]
@ECHO "What can I do for you today great one?"
NET USE G: \\\\servername\\hackershare1 /YES
NET USE I: \\\\servername\\adminshare2 /YES

[User-fred]
@ECHO "Hello there Fred!"
NET USE F: \\\\servername\\fredsspecialshare /YES

[OS-WfWg]
@ECHO "Time to upgrade it?"

# End configuration file

usage: ntlogon [-g | --group=groupname] 
               [-u | --user=username]
               [-o | --os=osname]
               [-m | --machine=netbiosname]
               [-f | --templatefile=filename]
               [-d | --dir=netlogon directory]
               [-v | --version]
               [-h | --help]
               [--pause]
               [--debug]
""" 
#   
#" This quote mark is an artifact of the inability of my editor to
#  correctly colour code anything after the triple-quoted docstring.
#  if your editor does not have this flaw, feel free to remove it.


import sys
import getopt
import re
import string
import os

version = "ntlogon.py v0.8"

def buildScript(buf, sections, group, user, ostype, machine, debug, pause):
    """
    buildScript() Takes the contents of the template file and builds
    a DOS batch file to be executed as an NT logon script. It does this
    by determining which sections of the configuration file should be included
    and creating a list object that contains each line contained in each
    included section.  The list object is then returned to the calling 
    routine.

    All comments (#) are removed. A REM is inserted to show
    which section of the configuration file each line comes from.
    We leave blanklines as they are sometimes useful for debugging

    We also replace all of the Samba macros (e.g., %U, %G, %a, %m) with their
    expanded versions which have been passed to us by smbd
    """
    hdrstring   = ''
    script = []

    #
    # These are the Samba macros that we currently know about.
    # any user defined macros will also be added to this dictionary.
    # We do not store the % sign as part of the macro name.
    # The replace routine will prepend the % sign to all possible
    # replacements.
    # 
    macros = {
        		'U': user,
                'G': group,
                'a': ostype,
                'm': machine
             }

    #
    # Process each section defined in the list sections
    #
    for s in sections:
        # print 'searching for: ' + s

        idx = 0

        while idx < len(buf):
            ln = buf[idx]

            #
            # We need to set up a regex for each possible section we
            # know about. This is slightly complicated due to the fact
            # that section headers contain user defined text.
            #
            if s == 'Global':
                hdrstring = '\[ *' + s + ' *\]'
            elif s == 'Group':
                hdrstring = '\[ *' + s + ' *- *' + group + ' *\]'
            elif s == 'User':
                hdrstring = '\[ *' + s + ' *- *' + user + ' *\]'
            elif s == 'OS':
                hdrstring = '\[ *' + s + ' *- *' + ostype + ' *\]'
            elif s == 'Machine':
	        hdrstring = '\[ *' + s + ' *- *' + machine + ' *\]'

            #
            # See if we have found a section header
            #
            if re.search(r'(?i)' + hdrstring, ln):
                idx = idx + 1   # increment the counter to move to the next
                                # line.

                x = re.match(r'([^#\r\n]*)', ln)    # Determine the section
                                                    # name and strip out CR/LF
                                                    # and comment information

                if debug:
                    print 'rem ' + x.group(1) + ' commands'
                else:
                    # create the rem at the beginning of each section of the
                    # logon script.
                    script.append('rem ' + x.group(1) + ' commands') 

                #
                # process each line until we have found another section
                # header
                #
                while not re.search(r'.*\[.*\].*', buf[idx]):

                    #
                    # strip comments and line endings
                    #
                    x = re.match(r'([^#\r\n]*)', buf[idx])

                    if string.strip(x.group(1)) != '' :
                        # if there is still content  after stripping comments and
                        # line endings then this is a line to process

                        line = x.group(1)

                        #
                        # Check to see if this is a macro definition line
                        #
                        vardef = re.match(r'(.*)=(.*)', line)

                        if vardef:
                            varname = string.strip(vardef.group(1))		# Strip leading and
                            varsub  = string.strip(vardef.group(2))		# and trailing spaces

                            if varname == '':
                                print "Error: No substition name specified line: %d" % idx
                                sys.exit(1)

                            if varsub == '':
                                print "Error: No substitution text provided line: %d" % idx
                                sys.exit(1)

                            if macros.has_key(varname):
                                print "Warning: macro %s redefined line: %d" % (varname, idx)

                            macros[varname] = varsub
                            idx = idx + 1
                            continue

                        #
                        # Replace all the  macros that we currently
                        # know about.
                        #
                        # Iterate over the dictionary that contains all known
                        # macro substitutions.
                        #
                        # We test for a macro name by prepending % to each dictionary
                        # key.
                        #
                        for varname in macros.keys():
                            line = re.sub(r'%' + varname + r'(\W)',
                                          macros[varname] + r'\1', line)

                        if debug:
                            print line
                            if pause:
                                print 'pause'
                        else:
                            script.append(line)

                    idx = idx + 1

                    if idx == len(buf):
                        break   # if we have reached the end of the file
                                # stop processing.

            idx = idx + 1   # increment the line counter

        if debug:
            print ''
        else:
            script.append('')

    return script

# End buildScript()

def run():
    """
    run() everything starts here. The main routine reads the command line
    arguments, opens and reads the configuration file.
    """
    configfile  = '/etc/ntlogon.conf'   # Default configuration file
    group       = ''                    # Default group
    user        = ''                    # Default user
    ostype      = ''                    # Default os
    machine     = ''			# Default machine type
    outfile     = 'logon.bat'           # Default batch file name
                                        #   this file name WILL take on the form
                                        #   username.bat if a username is specified
    debug       = 0                     # Default debugging mode
    pause		= 0						# Default pause mode
    outdir      = '/usr/local/samba/netlogon/'   # Default netlogon directory

    sections    = ['Global', 'Machine', 'OS', 'Group', 'User'] # Currently supported
                                                    # configuration file 
                                                    # sections

    options, args = getopt.getopt(sys.argv[1:], 'd:f:g:ho:u:m:v', 
                                 ['templatefile=', 
                                  'group=',
                                  'help',
                                  'os=',
                                  'user=',
                                  'machine=',
                                  'dir=',
                                  'version',
                                  'pause',
                                  'debug'])

    #
    # Process the command line arguments
    #
    for i in options:
        # template file to process
        if (i[0] == '-f') or (i[0] == '--templatefile'):
            configfile = i[1]
            # print 'configfile = ' + configfile

        # define the group to be used
        elif (i[0] == '-g') or (i[0] == '--group'):
            group = i[1]
            # print 'group = ' + group

        # define the os type
        elif (i[0] == '-o') or (i[0] == '--os'):
            ostype = i[1]
            # print 'os = ' + os

        # define the user
        elif (i[0] == '-u') or (i[0] == '--user'):
            user = i[1]
            outfile = user + '.bat' # Setup the output file name
            # print 'user = ' + user

        # define the machine
        elif (i[0] == '-m') or (i[0] == '--machine'):
            machine = i[1]

        # define the netlogon directory
        elif (i[0] == '-d') or (i[0] == '--dir'):
            outdir = i[1]
            # print 'outdir = ' + outdir

        # if we are asked to turn on debug info, do so.
        elif (i[0] == '--debug'):
            debug = 1
            # print 'debug = ' + debug

        # if we are asked to turn on the automatic pause functionality, do so
        elif (i[0] == '--pause'):
            pause = 1
            # print 'pause = ' + pause

        # if we are asked for the version number, print it.
        elif (i[0] == '-v') or (i[0] == '--version'):
            print version
            sys.exit(0)

        # if we are asked for help print the docstring.
        elif (i[0] == '-h') or (i[0] == '--help'):
            print __doc__
            sys.exit(0)

    #
    # open the configuration file
    #    
    try:
        iFile = open(configfile, 'r')
    except IOError:
        print 'Unable to open configuration file: ' + configfile
        sys.exit(1)


    #
    # open the output file
    #    
    if not debug:
        try:
            oFile = open(outdir + outfile, 'w')
        except IOError:
            print 'Unable to open logon script file: ' + outdir + outfile
            sys.exit(1)

    buf = iFile.readlines() # read in the entire configuration file

    #
    # call the script building routine
    #
    script = buildScript(buf, sections, group, user, ostype, machine, debug, pause)

    #
    # write out the script file
    #
    if not debug:
        for ln in script:
            oFile.write(ln + '\r\n')
            if pause:
                if string.strip(ln) != '':			# Because whitespace
                    oFile.write('pause' + '\r\n')	# is a useful tool, we
                    								# don't put pauses after
                                                    # an empty line.


# End run()

#
# immediate-mode commands, for drag-and-drop or execfile() execution
#
if __name__ == '__main__':
    run()
else:
    print "Module ntlogon.py imported."
    print "To run, type: ntlogon.run()"
    print "To reload after changes to the source, type: reload(ntlogon)"

#
# End NTLogon.py
#