"Fossies" - the Fresh Open Source Software Archive

Member "mkapachepw-1.121/mkapachepw.py" (12 Apr 2005, 12737 Bytes) of package /linux/www/old/mkapachepw-1.121.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "mkapachepw.py" see the Fossies "Dox" file reference documentation.

    1 #!/usr/bin/env python
    2 # mkapachepw.py
    3 # Generate Apache-Compatible Password And Group Files
    4 # From Unix System Passwords And Groups.
    5 #
    6 # Copyright (c) 2005 TundraWare Inc.  All Rights Reserved.
    7 # For Updates See:  http://www.tundraware.com/Software/mkapachepw
    8 
    9 # Program Information
   10 
   11 PROGNAME = "mkapachepw"
   12 RCSID = "$Id: mkapachepw.py,v 1.121 2005/04/12 07:10:35 root Exp $"
   13 VERSION = RCSID.split()[2]
   14 
   15 # Copyright Information
   16 
   17 CPRT         = "(c)"
   18 DATE         = "2005"
   19 OWNER        = "TundraWare Inc."
   20 RIGHTS       = "All Rights Reserved"
   21 COPYRIGHT    = "Copyright %s %s %s  %s. " % (CPRT, DATE, OWNER, RIGHTS)
   22 
   23 
   24 #----------------------------------------------------------#
   25 #            Variables User Might Change                   #
   26 #----------------------------------------------------------#
   27 
   28 BOGUSID  = 100000               # Fake GID/UID used when external files
   29 GRFILE   = "./.htgroups"        # Group output file  
   30 USRFILE  = "./.htusers"         # User output file
   31 STARTUID = 100                  # User IDs below this ignored
   32 STARTGID = 100                  # Group IDS below this ignored
   33 
   34 
   35 
   36 #------------------- Nothing Below Here Should Need Changing ------------------#
   37 
   38 
   39 #----------------------------------------------------------#
   40 #                       Imports                            #
   41 #----------------------------------------------------------#
   42 
   43 import getopt
   44 import grp
   45 import os
   46 import pwd
   47 from socket import getfqdn
   48 import sys
   49 import time
   50 
   51 
   52 #----------------------------------------------------------#
   53 #                 Aliases & Redefinitions                  #
   54 #----------------------------------------------------------#
   55 
   56 
   57 
   58 #----------------------------------------------------------#
   59 #                Constants & Literals                      #
   60 #----------------------------------------------------------#
   61 
   62 
   63 
   64 #####
   65 # Constants
   66 #####
   67 
   68 
   69 
   70 #####
   71 # Literals
   72 #####
   73 
   74 CMDLINE   = "# Command Line: %s\n" % " ".join(sys.argv)
   75 TIMESTAMP = "# Created By %s %s On %s At %s\n" % (PROGNAME, VERSION, getfqdn(), time.asctime())
   76 
   77 GID       = 'GID'
   78 GROUP     = 'Group'
   79 UID       = 'UID'
   80 USER      = 'User'
   81 
   82 
   83 #----------------------------------------------------------#
   84 #              Prompts, & Application Strings              #
   85 #----------------------------------------------------------#
   86 
   87 
   88 #####
   89 # Error And Warning Messages
   90 #####
   91 
   92 eABORT          = "Aborting ..."
   93 eERROR          = "ERROR"
   94 eFILEOPEN       = "Cannot Open File '%s'."
   95 eINVALIDID      = "'%s' Is An Invalid %s ID."
   96 eINVALIDNAME    = "'%s' Is An Invalid %s Name."
   97 eINVALIDSTART   = "Invalid Starting %s, '%s' - Must Be An Integer Value."
   98 eNOPREFIX       = "'%s' Must Be Prefixed With '+' or '-' To Indicate Desired Action."
   99 
  100 wCOLLIDE        = "'%s' Entry In %s Conflicts With Entry Already In %s List."
  101 wOVERWRITE      = "Overwriting..."
  102 wWARNING        = "WARNING"
  103 
  104 
  105 #####
  106 # Usage Prompts
  107 #####
  108 
  109 uTable = [PROGNAME + " " + VERSION + " - %s\n" % COPYRIGHT,
  110           "usage:  " + PROGNAME + " [-sGUguIicqOohv]",
  111           "   where,",
  112           "          -s       do not process system password/group files (default: process these files)",
  113           "          -G       list of groups to include (+group | +GID) or exclude (-group | -GID) (default: none)",
  114           "          -U       list of users to include (+user | + UID) or exclude (-user | -UID) (default: none)",
  115           "          -g #     smallest GID to include in output (default: 100)",
  116           "          -u #     smallest UID to include in output (default: 100)",
  117           "          -I file  include file containing other group information (default: none)",
  118           "          -i file  include file containing other user information (default: none)",
  119           "          -c       do not permit entries to be overwritten (default: allow - only warn)",
  120           "          -q       quiet mode - suppresses warning messages",
  121           "          -O file  group file name, - selects stdout (default: ./.htgroups)",
  122           "          -o file  user file name, - selects stdout  (default: ./.htusers)",
  123           "          -h       print this help information",
  124           "          -v       print detailed version information",
  125           ]
  126 
  127 
  128 #----------------------------------------------------------#
  129 #          Global Variables & Data Structures              #
  130 #----------------------------------------------------------#
  131 
  132 enumerated         = []          # Place to store command line in/exclude enumerations
  133 includes           = []          # Place to store names of files to include
  134 
  135 groups             = {}          # Place to store group information
  136 users              = {}          # Place to store user information
  137 
  138 ALLOWCOLLISIONS    = True        # Allow entries to overwrite each other (with warning)
  139 QUIET              = False       # Suppress display of warning messages
  140 SYSFILES           = True        # Flag to enable/disable inclusion of system group/pw
  141 
  142 
  143 #--------------------------- Code Begins Here ---------------------------------#
  144 
  145 
  146 #----------------------------------------------------------#
  147 #             Object Base Class Definitions                #
  148 #----------------------------------------------------------#
  149 
  150     
  151 
  152 #----------------------------------------------------------#
  153 #             Supporting Function Definitions              #
  154 #----------------------------------------------------------#
  155 
  156 
  157 #####
  158 # Print An Error Message
  159 #####
  160 
  161 def ErrorMsg(emsg, Warning=False, Action=eABORT):
  162 
  163     if Warning:
  164         if QUIET:     # Quiet mode suppresses warning messages
  165             return
  166         prompt = wWARNING
  167     else:
  168         prompt = eERROR
  169 
  170     print PROGNAME + " " + VERSION + " " + prompt + ": " + emsg + " " + Action
  171 
  172 # End of 'ErrorMsg()'
  173 
  174 
  175 #####
  176 # Print Usage Information
  177 #####
  178 
  179 def Usage():
  180     for line in uTable:
  181         print line
  182 
  183 # End of 'Usage()'
  184 
  185 
  186 #####
  187 # Process An Enumerated List Of Groups/Users To Include Or Exclude.
  188 #
  189 # The 'items' argument must be a string with the names or numbers to
  190 # process, with a '-' or '+' prepended to indicate Delete or Add,
  191 # respectively.
  192 #####
  193 
  194 def ProcessEnumeratedList(items, lookup, name):
  195 
  196     if name == GROUP:
  197         master = groups
  198     else:
  199         master = users
  200         
  201     for item in items.split():
  202         orig = item
  203         
  204         # Verify argument is in correct format and determine type of
  205         # operation desired.
  206 
  207         if item[0] == '-':
  208             additem = False
  209 
  210         elif item[0] == '+':
  211             additem = True
  212 
  213         else:
  214             ErrorMsg(eNOPREFIX % item)
  215             sys.exit(2)
  216 
  217         item = item[1:]     # We just need the item Name/ID portion
  218 
  219         # Convert GIDs and UIDs to names first
  220         try:
  221             item = int(item)
  222 
  223             # Handle the case where the ID does not exist
  224             try:
  225                 item = lookup(item)[0]
  226 
  227             except:
  228                 ErrorMsg(eINVALIDID % (orig[1:], name))
  229                 sys.exit(2)
  230 
  231         # If not, assume it is a name and look it up
  232         except ValueError:
  233 
  234             # Make sure it even exists
  235 
  236             if item not in master:
  237                 ErrorMsg(eINVALIDNAME % (item, name))
  238                 sys.exit(2)
  239 
  240         # Do the actual in/exclusion
  241 
  242         # Include
  243         if additem:
  244             master[item][2] = True   # Mark entry as protected
  245 
  246         # Exclude
  247         else:
  248             del master[item]
  249 
  250 # End of 'ProcessEnumeratedList()'
  251 
  252 
  253 #####
  254 # Read A File Into A Local List, Stripping Newlines, And
  255 # Suppressing Blank Lines
  256 #####
  257 
  258 def ReadFile(filename):
  259     
  260     temp = []
  261     try:
  262         f = open(filename)
  263         for l in f.readlines():
  264             if l[-1] == '\n':            # Get rid of trailing newlines
  265                 l = l[:-1] 
  266             l = l.split('#')[0].strip()  # Get rid of comments
  267 
  268             if l:                        # Add any non-blank lines
  269                 name, members = l.split(':')
  270                 members = members.split()
  271                 temp.append([name, members])
  272         f.close()
  273 
  274     except:
  275         ErrorMsg(eFILEOPEN % filename)
  276         sys.exit(1)
  277 
  278     return temp
  279 
  280 # End of 'ReadFile()'
  281 
  282 
  283 #----------------------------------------------------------#
  284 #                    Program Entry Point                   #
  285 #----------------------------------------------------------#
  286 
  287 
  288 #####
  289 # Command line processing - Process any options set in the
  290 # environment first, and then those given on the command line
  291 #####
  292 
  293 OPTIONS = sys.argv[1:]
  294 envopt = os.getenv(PROGNAME.upper())
  295 if envopt:
  296     OPTIONS = envopt.split() + OPTIONS
  297 
  298 try:
  299     opts, args = getopt.getopt(OPTIONS, '-sG:U:g:u:I:i:cqO:o:hv')
  300 except getopt.GetoptError:
  301     Usage()
  302     sys.exit(1)
  303 
  304 # This command line accepts no args
  305 if args:
  306     Usage()
  307     sys.exit(1)
  308 
  309 
  310 for opt, val in opts:
  311     if opt == "-s":
  312         SYSFILES = False
  313     if opt == "-G":
  314         enumerated.append([val, grp.getgrgid, GROUP])
  315     if opt == "-U":
  316         enumerated.append([val, pwd.getpwuid, USER])
  317     if opt == "-g":
  318         try:
  319             STARTGID=int(val)
  320         except:
  321             ErrorMsg(eINVALIDSTART % (GID, val))
  322             sys.exit(1)
  323     if opt == "-u":
  324         try:
  325             STARTUID=int(val)
  326         except:
  327             ErrorMsg(eINVALIDSTART % (UID, val))
  328             sys.exit(1)
  329     if opt == "-I":
  330         includes.append([val, groups])
  331     if opt == "-i":
  332         includes.append([val, users])
  333     if opt == "-c":
  334         ALLOWCOLLISIONS = False
  335     if opt == "-q":
  336         QUIET = True
  337     if opt == "-O":
  338         GRFILE = val
  339     if opt == "-o":
  340         USRFILE = val
  341     if opt == "-h":
  342         Usage()
  343         sys.exit(0)
  344     if opt == "-v":
  345         print RCSID
  346         sys.exit(0)
  347 
  348 #####
  349 # Build List Of System Groups And Users
  350 #####
  351 
  352 
  353 # Can be suppressed with the -s command line argument
  354 
  355 if SYSFILES:
  356     
  357     Protected = False
  358 
  359     #####
  360     # Build List Of Groups
  361     #####
  362 
  363     for group in grp.getgrall():
  364 
  365         gname, gpw, gid, gmembers = group[:4]
  366 
  367         groups[gname] = [gid, [], Protected]
  368         for member in gmembers:
  369             groups[gname][1].append(member)
  370 
  371     #####
  372     # Build A List Of Users
  373     #####
  374 
  375     for user in pwd.getpwall():
  376 
  377         uname, pw, uid, gid = user[:4]
  378         gname = grp.getgrgid(gid)[0]
  379 
  380         users[uname] = [uid, pw, Protected]
  381 
  382         if uname not in groups[gname][1]:
  383             groups[gname][1].append(uname)
  384 
  385 
  386 #####
  387 # Process Included Files
  388 #####
  389 
  390 for include in includes:
  391 
  392     # Read the file into a temporary list
  393     filename, db = include[:]
  394     temp = ReadFile(filename)
  395 
  396     # Add each entry to the appropriate in-memory database
  397     for entry in temp:
  398 
  399         # Group entries have a list of members
  400         if db == groups:
  401             members = entry[1]
  402             name = GROUP
  403             
  404         # User entries have a single password
  405         else:
  406             members = entry[1][0]
  407             name = USER
  408 
  409         # See if this entry will overwrite an existing one
  410         # If it will, warn if collisions are permitted
  411         # Error out otherwise
  412 
  413         if entry[0] in db:
  414 
  415             if ALLOWCOLLISIONS:
  416                 ErrorMsg(wCOLLIDE % (entry[0], filename, name), Warning=True, Action=wOVERWRITE)
  417             else:
  418                 ErrorMsg(wCOLLIDE % (entry[0], filename, name))
  419                 sys.exit(4)
  420 
  421         db[entry[0]] = [BOGUSID, members, False]
  422 
  423 
  424 #####
  425 # Process Any Enumerated Inclusions/Exclusions
  426 #####
  427 
  428 for enum in enumerated:
  429     ProcessEnumeratedList(*enum)
  430 
  431 
  432 #####
  433 # Write Out The Files
  434 #####
  435 
  436 # Files Should Be Read-Only
  437 
  438 os.umask(0377)
  439 
  440 # Group File
  441 
  442 try:
  443     if GRFILE == '-':
  444         grfile = sys.stdout
  445     else:
  446         grfile = open(GRFILE, "w")
  447 except:
  448     ErrorMsg(eFILEOPEN % GRFILE)
  449     sys.exit(3)
  450     
  451 grfile.write(TIMESTAMP)
  452 grfile.write(CMDLINE)
  453 
  454 # Write out groups if they are either protected or >= specified starting ID
  455 
  456 gnames = groups.keys()
  457 gnames.sort()
  458 for gname in gnames:
  459     if (groups[gname][2]) or (groups[gname][0] >= STARTGID):
  460         grfile.write("%s: %s\n" % (gname, " ".join(groups[gname][1])))
  461 
  462 grfile.close()
  463 
  464 
  465 # Password File
  466 
  467 try:
  468     if USRFILE == '-':
  469         pwfile = sys.stdout
  470     else:
  471         pwfile = open(USRFILE, "w")
  472 except:
  473     ErrorMsg(eFILEOPEN % USRFILE)
  474     sys.exit(3)
  475     
  476 pwfile.write(TIMESTAMP)
  477 pwfile.write(CMDLINE)
  478 
  479 # Write out users if they are either protected or >= specified starting ID
  480 # Unless explicitly protected, any account that has '*' as a password
  481 # (thus indicating it does not support login), will be suppressed.
  482 
  483 unames = users.keys()
  484 unames.sort()
  485 for uname in unames:
  486     if (users[uname][2]) or ((users[uname][0] >= STARTUID) and (users[uname][1] != '*')):
  487         pwfile.write("%s:%s\n" % (uname, users[uname][1]))
  488 
  489 pwfile.close()