My Python Notes

Saturday 18th September 2004

(Re)Introducing PyKey

An update on my password generation effort, previously known simply as "Passgen". Say hello to PyKey. I didn't give it that much thought, but the name kind of popped up while I was trying out different combinations using 'py'.

It even has its own home:

http://sajjadzaidi.com/pykey/

I've also added a difficulty option which right now just prints out random words or combinations of words from a dictionary at the 'easy' level. 'Medium' does what passgen did before, i.e. mash dictionary words together and manipulate random characters. 'Hard' spits out random characters which are usually very hard to remember.

The medium and hard levels make sure the passwords have at least a digit, upper case letter, lower case letter and a special character so they should be pretty secure. The easy passwords should be crackable in a matter of minutes or hours unless other security methods (such as limited retries) are used.

Here is the demo:

http://sajjadzaidi.com/pykey/pykey.py

and the source:

http://sajjadzaidi.com/pykey/pykey.txt

Use './pykey.py --help' for information on how to use it from the command line.

Now bring it on with the "I f#$@^& hate pykey" jokes.

Posted at 21:26pm PKT Comments |

Thursday 9th September 2004

Password Generator

One of the most important things when it comes to security is good passwords. Ideally, a password should be of reasonable, but random length and consist of at least one digit, meta-character, upper-case letter and lower-case letter. This may seem extreme, but most people tend to forget that usually passwords can consist of phrases and words can be easily modified to match this criteria.

For a while now, I've been using simple scripts to generate totally random, really difficult passwords (or passphrases, which really is more appropriate). Although the human mind is quite amazing at storing this kind of information, memorizing a few dozen of these can get tedious.

The script I currently use, transforms randomly selected dictionary words to generate a passphrase that matches the above criteria. I've written it in Python and will keep on adding more options and features as new ideas come to mind.

One idea I have is to generate random, non-dictionary words which are easy to remember and pronounce, but can't be cracked using a simple dictionary attack or even one which tries all the possible substitutes (such as '@' in place of an 'a'). I memoramember fincovering another password generator that utiliates like this, though writing a function to test the readapronability could be an abonomatorically daunteresting task. Reminds me of the BlackAdder III episode about the origins of the Dictionary. :-)

Give 'passgen.py' a try here and please do suggest a better name. I'm thinking along the lines of 'pypass' or 'pygen':

http://sajjadzaidi.com/python/passgen.py

The code is available here:

http://sajjadzaidi.com/python/passgen.txt

Please note that this is more of a demo. Since the generated passwords are transmitted in plain text to your browser (unless you are using SSL), there is a possibility of them being picked up on the way. The same script will run from the command line so run it from there.

Posted at 17:44pm PKT Comments |

20th January 2003

Posting here after a long time. Right now, Im working on a Python CGI script that restarts services on a system by using 'sudo'.

My personal project that I am working on is a database that stores all kinds of information about a server. The plan is to have a Python application that can be run either as a CGI, from the command line or as an X application if the DISPLAY variable is set. The last option is the hardest so may not be implemented. Database would be Postgresql.

25th October 2002

I realised there wasnt any automated way to delete users with the below script, so today I added that functinality and ended up rewriting the whole script.

#!/usr/bin/python

import sys,os,string

def clearSMTPDb(smtpUser):
	# Remove the user from the SMTP password file
	userList = "/etc/exim/users"
	tmpUserList = "/etc/exim/users.new"
	if os.path.exists("%s" % userList):
		f = open("%s" % userList)
		p = open("%s" % tmpUserList, 'w')
		fullList = f.readline()
		while fullList:
			alreadyExist = string.find(fullList, "%s:" % smtpUser)
			if alreadyExist == 0:
				fullList = f.readline()
				continue
			p.write("%s" % fullList)
			fullList = f.readline()
		f.close()
		p.close()

		os.rename(tmpUserList, userList)
	return()

def changePassword(accountName):
	from getpass import getpass
	from crypt import crypt

	# Prompt for Password
	print 'Adding only APOP password for %s.' % accountName
	userPass = getpass("New password: ")
	userPass2 = getpass("Retype new password: ")

	# Simple check to make sure passwords match
	if userPass != userPass2:
		print 'Mismatch -- password unchanged.'
		sys.exit(1)

	clearSMTPDb(accountName)

	userList = "/etc/exim/users"

	# Add user and encrypted password
	f = open("%s" % userList, 'a')
	f.write("%s:%s\n" % (accountName,crypt(userPass,accountName)))
	f.close()

	# Run the original popauth command to change the qpopper password
	c = os.popen("/usr/sbin/popauth -user %s '%s'" % (accountName,userPass))
	return()

def deleteUser(accountName):
	clearSMTPDb(accountName)

	# Run the original popauth command to delete the user from QPopper's database
	c = os.popen("/usr/sbin/popauth -delete %s" % accountName)
	# This will remove the account from the system, but keep the home directory
	s = os.popen("userdel %s" % accountName)

	return()


# Make sure at least 2 arguments were given. Exit if not.
if len(sys.argv) > 2:
        userName = sys.argv[2]
else:
	sys.exit(1)


# Check whether a user is to be deleted or its password changed
if sys.argv[1] == "-delete":
	try:
		deleteUser(userName)
	except:
		sys.exit(1)
else:
	try:
		changePassword(userName)
	except:
		sys.exit(1)

sys.exit(0)
								

You can download it here

27th September 2002

I wrote this script to replace the binary installed by QPopper. It adds the encrypted password entry to Exim's user database.


#!/usr/bin/python

import sys,os,string
from getpass import getpass
from crypt import crypt

if len(sys.argv) > 2:
        userName = sys.argv[2]
else:
	sys.exit(1)

print 'Adding only APOP password for %s.' % userName
userPass = getpass("New password: ")
userPass2 = getpass("Retype new password: ")

if userPass != userPass2:
	print 'Mismatch -- password unchanged.'
	sys.exit(1)


userList = "/etc/exim/users"
tmpUserList = "/etc/exim/users.new"

f = open("%s" % userList)
p = open("%s" % tmpUserList, 'w')
fullList = f.readline()
while fullList:
	alreadyExist = string.find(fullList, "%s:" % userName)
	if alreadyExist == 0:
		fullList = f.readline()
		continue
	p.write("%s" % fullList)
	fullList = f.readline()
f.close()
p.close()

os.rename(tmpUserList, userList)

f = open("%s" % userList, 'a')
f.write("%s:%s\n" % (userName,crypt(userPass,userName)))
f.close()

c = os.popen("/usr/sbin/popauth -user %s '%s'" % (userName,userPass))

sys.exit(0)

								

20th September 2002

This small change can allow mailman to increment the subject number by updating it to a file in the list's main directory.

Edit 'Mailman/Handlers/CookHeaders.py' and append these lines to it:

def incrementSubject(listName):
    import paths
    serialFile = paths.prefix + "/lists/%s/prefix_serial" % listName
    try:
        f = open("%s" % serialFile)
        serialNumber = int(f.readline()) + 1
        f.close()
        f = open("%s" % serialFile, "w")
        f.write("%s" % serialNumber)
        f.close()
    except:
        try:
            f = open("%s" % serialFile, "w")
            serialNumber = 0
            f.write("%s" % serialNumber)
        except:
            return("")
    return("%s" % serialNumber)
								

Then, in the same file, change the line 'prefix = mlist.subject_prefix' to:

prefix = string.replace(mlist.subject_prefix,"#",incrementSubject(mlist.internal_name()))
								

Then go to the admin interface and add a '#' to the setting 'Prefix for subject line of list postings.' at the point you want the number to appear.