Newer
Older
mkapachepw / mkapachepw.py
#!/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()