| 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 | #
|
|---|