#!/usr/bin/python

# check password quality using cracklib given a new password, optionally the
# old password, and a list of ldap/gecos words via stdin, each on a line by
# itself (send an empty line if you want to skip the old password check)

# Copyright (c) 2008 Peter Palfrader

import sys, tempfile, os
import cracklib

def cleanup(dir):
  if not dir.startswith('/tmp/pwcheck-'):
    raise ValueError, 'cleanup got a weird dir to remove: '+dir
  for f in 'dict.hwm dict.pwd dict.pwi wordlist wordlist-cleaned'.split(' '):
    p = dir+'/'+f
    if os.path.exists(p):
      os.remove(p)
  if os.path.exists(dir):
    os.rmdir(dir)



crack_mkdict = None
crack_packer = None
for b in "/usr/sbin/crack_mkdict /usr/sbin/cracklib-format".split(' '):
  if os.path.exists(b):
    crack_mkdict = b
    break
for b in "/usr/sbin/crack_packer /usr/sbin/cracklib-packer".split(' '):
  if os.path.exists(b):
    crack_packer = b
    break
if crack_mkdict is None or crack_packer is None:
  print "Could not find crack formater or packer"
  sys.exit(1)


newpass = sys.stdin.readline().strip()
oldpass = sys.stdin.readline().strip()
ldapwords = map( lambda x: x.strip(), sys.stdin.readlines())

if oldpass == "":
  oldpass = None


cracklib.min_length = 11

# check against the default dictionary
try:
  cracklib.VeryFascistCheck(newpass, oldpass, '/var/cache/cracklib/cracklib_dict')
except ValueError, e:
  print e
  sys.exit(1)

# and against a dictionary created from the ldap info on this user
if len(ldapwords) > 0:
  # squeeze's cracklib-packer complains about '*' on input - it
  # says 'skipping line: 1'
  while '-' in ldapwords:
    ldapwords.remove('-')
  while '*' in ldapwords:
    ldapwords.remove('*')

  tmpdir = tempfile.mkdtemp('', 'pwcheck-')
  F = open(tmpdir+'/wordlist', "w")
  for w in ldapwords:
    F.write(w+"\n");
  for w1 in ldapwords:
    for w2 in ldapwords:
      F.write(w1+w2+"\n");
      F.write(w1[0]+w2+"\n");
  F.close()

  r = os.system(crack_mkdict+" "+tmpdir+"/wordlist > "+tmpdir+"/wordlist-cleaned")
  if r != 0:
    print "crack_mkdict returned non-zero exit status %d."%(r)
    cleanup(tmpdir)
    sys.exit(1)
  r = os.system(crack_packer+" "+tmpdir+"/dict < "+tmpdir+"/wordlist-cleaned > /dev/null")
  if r != 0:
    print "crack_packer returned non-zero exit status %d."%(r)
    cleanup(tmpdir)
    sys.exit(1)

  try:
    cracklib.VeryFascistCheck(newpass, None, tmpdir+"/dict")
  except ValueError, e:
    print "ldap data based check: "+str(e)
    cleanup(tmpdir)
    sys.exit(1)

  cleanup(tmpdir)

sys.exit(0)
