#!/usr/bin/env python # mkapachepw.py # Generate Apache-Compatible Password And Group Files # From Unix System Passwords And Groups. # # Copyright (c) 2005 TundraWare Inc. All Rights Reserved. # For Updates See: http://www.tundraware.com/Software/mkapachepw # Program Information PROGNAME = "mkapachepw" RCSID = "$Id: mkapachepw.py,v 1.107 2005/04/04 21:41:37 root Exp $" VERSION = RCSID.split()[2] # Copyright Information CPRT = "(c)" DATE = "2005" OWNER = "TundraWare Inc." RIGHTS = "All Rights Reserved" COPYRIGHT = "Copyright %s %s %s %s. " % (CPRT, DATE, OWNER, RIGHTS) #----------------------------------------------------------# # Variables User Might Change # #----------------------------------------------------------# GRFILE = "./.htgroups" # Group output file PWFILE = "./.htpasswords" # Password output file STARTUID = 100 # User IDs below this ignored STARTGID = 100 # Group IDS below this ignored #------------------- Nothing Below Here Should Need Changing ------------------# #----------------------------------------------------------# # Imports # #----------------------------------------------------------# import getopt import grp import os import pwd from socket import getfqdn import sys import time #----------------------------------------------------------# # Aliases & Redefinitions # #----------------------------------------------------------# #----------------------------------------------------------# # Constants & Literals # #----------------------------------------------------------# ##### # Constants ##### ##### # Literals ##### TIMESTAMP = "# Created By %s %s On %s At %s\n" % (PROGNAME, VERSION, getfqdn(), time.asctime()) #----------------------------------------------------------# # Prompts, & Application Strings # #----------------------------------------------------------# ##### # Error Messages ##### eERROR = "ERROR" ##### # Informational Messages ##### ##### # Usage Prompts ##### uTable = [PROGNAME + " " + VERSION + " - %s\n" % COPYRIGHT, "usage: " + PROGNAME + " [-GUfghpv] where,\n", " -G list of groups to include (+group) or exclude (-group) (default: none)", " -U list of users to include (+user) or exclude (-user) (default: none)", " -f file configuration file to use (default: none)", " -g # smallest GID to include in output (default: 100)", " -h print this help information", " -p # smallest UID to include in output (default: 100)", " -v print detailed version information", ] #----------------------------------------------------------# # Global Variables & Data Structures # #----------------------------------------------------------# CFGFILE = "" # Default is no config file groups = {} # Place to store group information users = {} # Place to store user information #--------------------------- Code Begins Here ---------------------------------# #----------------------------------------------------------# # Object Base Class Definitions # #----------------------------------------------------------# #----------------------------------------------------------# # Supporting Function Definitions # #----------------------------------------------------------# ##### # Print An Error Message ##### def ErrorMsg(emsg): print PROGNAME + " " + VERSION + " " + eERROR + ": " + emsg # End of 'ErrorMsg()' ##### # Print Usage Information ##### def Usage(): for line in uTable: print line # End of 'Usage()' ##### # Process An Enumerated List Of Groups/Users To Include Or Exclude. # # The 'items' argument must be a string with the names or numbers to # process, with a '-' or '+' prepended to indicate Delete or Add, # respectively. ##### def ProcessEnumeratedList(items, master, lookup, name): for item in items.split(): orig = item # Verify argument is in correct format and determine type of # operation desired. if item[0] == '-': additem = False elif item[0] == '+': additem = True else: ErrorMsg("'%s' Must Be Prefixed With '+' or '-' To Indicate Desired Action." % item) sys.exit(2) item = item[1:] # We just need the item ID portion # See if it's a GID/UID (a number) try: item = int(item) # Make sure it even exists if item not in master: ErrorMsg("'%s' Is An Invalid %s ID." % (item, name)) sys.exit(2) # If not, assume it is a name and look it up except ValueError: # Handle the case where the name does not exist try: item = lookup(item)[2] except: ErrorMsg("'%s' Is An Invalid %s Name." % (orig[1:], name)) sys.exit(2) print additem, item # Do the actual in/exclusion # Include if additem: master[item][2] = True # Mark entry as protected # Exclude else: del master[item] # End of 'ProcessEnumeratedList(()' #----------------------------------------------------------# # Program Entry Point # #----------------------------------------------------------# ##### # Build An Internal List Of Groups And Users Before Doing Anything Else. # Command Line Parsing May Need This Information. ##### Protected = False ##### # Build List Of Groups ##### for group in grp.getgrall(): gname, gpw, gid, gmembers = group[:4] groups[gid] = [gname, [], Protected] for member in gmembers: groups[gid][1].append(member) ##### # Build A List Of Users ##### for user in pwd.getpwall(): uname, pw, uid, gid = user[:4] users[uid] = [uname, pw, Protected] if uname not in groups[gid][1]: groups[gid][1].append(uname) ##### # Command line processing - Process any options set in the # environment first, and then those given on the command line ##### OPTIONS = sys.argv[1:] envopt = os.getenv(PROGNAME.upper()) if envopt: OPTIONS = envopt.split() + OPTIONS try: opts, args = getopt.getopt(OPTIONS, '-G:U:f:g:hp:v') except getopt.GetoptError: Usage() sys.exit(1) for opt, val in opts: if opt == "-G": ProcessEnumeratedList(val, groups, grp.getgrnam, "Group") if opt == "-U": ProcessEnumeratedList(val, users, pwd.getpwnam, "User") if opt == "-f": CFGFILE=val if opt == "-g": STARTGID=int(val) if opt == "-h": Usage() sys.exit(0) if opt == "-p": STARTUID=int(val) if opt == "-v": print RCSID sys.exit(0) print users, groups ##### # Write Out The Files ##### # Files Should Be Read-Only os.umask(0377) # Group File grfile = open(GRFILE, "w") grfile.write(TIMESTAMP) # Write out groups if they are either protected or >= specified starting ID for gid in groups: if (groups[gid][2]) or (gid >= STARTGID): grfile.write("%s: %s\n" % (groups[gid][0], " ".join(groups[gid][1]))) grfile.close() # Password File pwfile = open(PWFILE, "w") pwfile.write(TIMESTAMP) # Write out users if they are either protected or >= specified starting ID for uid in users: print users[uid] if (users[uid][2]) or (uid >= STARTUID): pwfile.write("%s:%s\n" % tuple(users[uid])[:2]) pwfile.close()