A set of copyright headers
[mirror/userdir-ldap.git] / ud-generate
index 1e8b392..e5c1ae3 100755 (executable)
@@ -6,12 +6,13 @@
 #   Copyright (c) 2003-2004  James Troup <troup@debian.org>
 #   Copyright (c) 2004-2005,7  Joey Schulze <joey@infodrom.org>
 #   Copyright (c) 2001-2007  Ryan Murray <rmurray@debian.org>
 #   Copyright (c) 2003-2004  James Troup <troup@debian.org>
 #   Copyright (c) 2004-2005,7  Joey Schulze <joey@infodrom.org>
 #   Copyright (c) 2001-2007  Ryan Murray <rmurray@debian.org>
-#   Copyright (c) 2008 Peter Palfrader <peter@palfrader.org>
+#   Copyright (c) 2008,2009,2010 Peter Palfrader <peter@palfrader.org>
 #   Copyright (c) 2008 Andreas Barth <aba@not.so.argh.org>
 #   Copyright (c) 2008 Mark Hymers <mhy@debian.org>
 #   Copyright (c) 2008 Luk Claes <luk@debian.org>
 #   Copyright (c) 2008 Thomas Viehmann <tv@beamnet.de>
 #   Copyright (c) 2009 Stephen Gran <steve@lobefin.net>
 #   Copyright (c) 2008 Andreas Barth <aba@not.so.argh.org>
 #   Copyright (c) 2008 Mark Hymers <mhy@debian.org>
 #   Copyright (c) 2008 Luk Claes <luk@debian.org>
 #   Copyright (c) 2008 Thomas Viehmann <tv@beamnet.de>
 #   Copyright (c) 2009 Stephen Gran <steve@lobefin.net>
+#   Copyright (c) 2010 Helmut Grohne <helmut@subdivi.de>
 #
 #   This program is free software; you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
 #
 #   This program is free software; you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
 import string, re, time, ldap, getopt, sys, os, pwd, posix, socket, base64, sha, shutil, errno, tarfile, grp
 from userdir_ldap import *
 from userdir_exceptions import *
 import string, re, time, ldap, getopt, sys, os, pwd, posix, socket, base64, sha, shutil, errno, tarfile, grp
 from userdir_ldap import *
 from userdir_exceptions import *
+try:
+   from cStringIO import StringIO
+except ImportError:
+   from StringIO import StringIO
 
 global Allowed
 global CurrentHost
 
 PasswdAttrs = None
 
 global Allowed
 global CurrentHost
 
 PasswdAttrs = None
+DebianUsers = None
 DisabledUsers = []
 DisabledUsers = []
-RetiredUsers = []
 GroupIDMap = {}
 SubGroupMap = {}
 Allowed = None
 GroupIDMap = {}
 SubGroupMap = {}
 Allowed = None
@@ -45,8 +50,10 @@ CurrentHost = ""
 UUID_FORMAT = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
 
 EmailCheck = re.compile("^([^ <>@]+@[^ ,<>@]+)?$")
 UUID_FORMAT = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
 
 EmailCheck = re.compile("^([^ <>@]+@[^ ,<>@]+)?$")
-BSMTPCheck = re.compile(".*mx 0 (gluck)\.debian\.org\..*",re.DOTALL)
-PurposeHostField = re.compile(r"\[\[([\*\-]?[a-z0-9.\-]*)(?:\|.*)?\]\]")
+BSMTPCheck = re.compile(".*mx 0 (master)\.debian\.org\..*",re.DOTALL)
+PurposeHostField = re.compile(r".*\[\[([\*\-]?[a-z0-9.\-]*)(?:\|.*)?\]\]")
+IsV6Addr = re.compile("^[a-fA-F0-9:]+$")
+IsDebianHost = re.compile(ConfModule.dns_hostmatch)
 DNSZone = ".debian.net"
 Keyrings = ConfModule.sync_keyrings.split(":")
 
 DNSZone = ".debian.net"
 Keyrings = ConfModule.sync_keyrings.split(":")
 
@@ -101,38 +108,44 @@ def IsRetired(DnRecord):
       # We'll give them a few extra days over what we said
       age = 6 * 31 * 24 * 60 * 60
       try:
       # We'll give them a few extra days over what we said
       age = 6 * 31 * 24 * 60 * 60
       try:
-         if (time.time() - time.mktime(time.strptime(line[1], "%Y-%m-%d"))) > age:
-            return True
+         return (time.time() - time.mktime(time.strptime(line[1], "%Y-%m-%d"))) > age
       except IndexError:
          return False
       except IndexError:
          return False
+      except ValueError:
+         return False
 
    return False
 
 
    return False
 
+def IsGidDebian(x):
+   try:
+      return int(GetAttr(x, "gidNumber", 0)) == 800
+   except ValueError:
+      return False
+
 # See if this user is in the group list
 def IsInGroup(DnRecord):
 # See if this user is in the group list
 def IsInGroup(DnRecord):
-  if Allowed == None:
-     return 1
+  if Allowed is None:
+     return True
 
   # See if the primary group is in the list
   if Allowed.has_key(GetAttr(DnRecord, "gidNumber")) != 0:
 
   # See if the primary group is in the list
   if Allowed.has_key(GetAttr(DnRecord, "gidNumber")) != 0:
-     return 1
+     return True
 
   # Check the host based ACL
   if DnRecord[1].has_key("allowedHost") != 0:
 
   # Check the host based ACL
   if DnRecord[1].has_key("allowedHost") != 0:
-     for I in DnRecord[1]["allowedHost"]:
-        if CurrentHost == I:
-           return 1
+     if CurrentHost in DnRecord[1]["allowedHost"]:
+        return True
 
   # See if there are supplementary groups
   if DnRecord[1].has_key("supplementaryGid") == 0:
 
   # See if there are supplementary groups
   if DnRecord[1].has_key("supplementaryGid") == 0:
-     return 0
+     return False
 
   supgroups=[]
   addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord, "uid"))
   for g in supgroups:
      if Allowed.has_key(g):
 
   supgroups=[]
   addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord, "uid"))
   for g in supgroups:
      if Allowed.has_key(g):
-        return 1
-  return 0
+        return True
+  return False
 
 def Die(File, F, Fdb):
    if F != None:
 
 def Die(File, F, Fdb):
    if F != None:
@@ -157,7 +170,7 @@ def Done(File, F, Fdb):
       os.rename(File + ".tdb.tmp", File + ".tdb")
 
 # Generate the password list
       os.rename(File + ".tdb.tmp", File + ".tdb")
 
 # Generate the password list
-def GenPasswd(l, File, HomePrefix, PwdMarker):
+def GenPasswd(File, HomePrefix, PwdMarker):
    F = None
    try:
       F = open(File + ".tdb.tmp", "w")
    F = None
    try:
       F = open(File + ".tdb.tmp", "w")
@@ -168,7 +181,7 @@ def GenPasswd(l, File, HomePrefix, PwdMarker):
      
       I = 0
       for x in PasswdAttrs:
      
       I = 0
       for x in PasswdAttrs:
-         if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
+         if x[1].has_key("uidNumber") == 0 or not IsInGroup(x):
             continue
      
          # Do not let people try to buffer overflow some busted passwd parser.
             continue
      
          # Do not let people try to buffer overflow some busted passwd parser.
@@ -198,7 +211,7 @@ def GenPasswd(l, File, HomePrefix, PwdMarker):
    return userlist
 
 # Generate the shadow list
    return userlist
 
 # Generate the shadow list
-def GenShadow(l, File):
+def GenShadow(File):
    F = None
    try:
       OldMask = os.umask(0077)
    F = None
    try:
       OldMask = os.umask(0077)
@@ -210,7 +223,7 @@ def GenShadow(l, File):
      
       I = 0
       for x in PasswdAttrs:
      
       I = 0
       for x in PasswdAttrs:
-         if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
+         if x[1].has_key("uidNumber") == 0 or not IsInGroup(x):
             continue
      
          Pass = GetAttr(x, "userPassword")
             continue
      
          Pass = GetAttr(x, "userPassword")
@@ -244,7 +257,7 @@ def GenShadow(l, File):
    Done(File, None, F)
 
 # Generate the sudo passwd file
    Done(File, None, F)
 
 # Generate the sudo passwd file
-def GenShadowSudo(l, File, untrusted):
+def GenShadowSudo(File, untrusted):
    F = None
    try:
       OldMask = os.umask(0077)
    F = None
    try:
       OldMask = os.umask(0077)
@@ -256,7 +269,7 @@ def GenShadowSudo(l, File, untrusted):
      
       for x in PasswdAttrs:
          Pass = '*'
      
       for x in PasswdAttrs:
          Pass = '*'
-         if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
+         if x[1].has_key("uidNumber") == 0 or not IsInGroup(x):
             continue
      
          if x[1].has_key('sudoPassword'):
             continue
      
          if x[1].has_key('sudoPassword'):
@@ -280,7 +293,7 @@ def GenShadowSudo(l, File, untrusted):
                   continue
                Pass = cryptedpass
                if for_this_host: # this makes sure we take a per-host entry over the for-all entry
                   continue
                Pass = cryptedpass
                if for_this_host: # this makes sure we take a per-host entry over the for-all entry
-                 break
+                  break
             if len(Pass) > 50:
                Pass = '*'
      
             if len(Pass) > 50:
                Pass = '*'
      
@@ -295,9 +308,8 @@ def GenShadowSudo(l, File, untrusted):
    Done(File, F, None)
 
 # Generate the shadow list
    Done(File, F, None)
 
 # Generate the shadow list
-def GenSSHShadow(l):
+def GenSSHShadow():
    # Fetch all the users
    # Fetch all the users
-   singlefile = None
    userfiles = []
 
    global PasswdAttrs
    userfiles = []
 
    global PasswdAttrs
@@ -307,9 +319,6 @@ def GenSSHShadow(l):
 
    for x in PasswdAttrs:
 
 
    for x in PasswdAttrs:
 
-      if x in DisabledUsers:
-         continue
-
       if x[1].has_key("uidNumber") == 0 or \
          x[1].has_key("sshRSAAuthKey") == 0:
          continue
       if x[1].has_key("uidNumber") == 0 or \
          x[1].has_key("sshRSAAuthKey") == 0:
          continue
@@ -333,9 +342,11 @@ def GenSSHShadow(l):
 
       # Oops, something unspeakable happened.
       except IOError:
 
       # Oops, something unspeakable happened.
       except IOError:
-          Die(File, F, None)
-          Die(masterFileName, masterFile, None)
-          raise
+         Die(File, F, None)
+         # As neither masterFileName nor masterFile are defined at any point
+         # this will raise a NameError.
+         Die(masterFileName, masterFile, None)
+         raise
 
    return userfiles
 
 
    return userfiles
 
@@ -381,7 +392,20 @@ def GenSSHtarballs(userlist, SSHFiles, grouprevmap, target):
       to.uname = f
       to.gname = grname
       to.mode  = 0400
       to.uname = f
       to.gname = grname
       to.mode  = 0400
-      tf.addfile(to, file(os.path.join(GlobalDir, 'userkeys', f)))
+
+      contents = file(os.path.join(GlobalDir, 'userkeys', f)).read()
+      lines = []
+      for line in contents.splitlines():
+         if line.startswith("allowed_hosts=") and ' ' in line:
+            machines, line = line.split('=', 1)[1].split(' ', 1)
+            if CurrentHost not in machines.split(','):
+               continue # skip this key
+         lines.append(line)
+      if not lines:
+         continue # no keys for this host
+      contents = "\n".join(lines) + "\n"
+      to.size = len(contents)
+      tf.addfile(to, StringIO(contents))
 
    tf.close()
    os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
 
    tf.close()
    os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
@@ -400,7 +424,7 @@ def addGroups(existingGroups, newGroups, uid):
 
       # let's see if we handled this group already
       if group in existingGroups:
 
       # let's see if we handled this group already
       if group in existingGroups:
-        continue
+         continue
 
       if not GroupIDMap.has_key(group):
          print "Group", group, "does not exist but", uid, "is in it"
 
       if not GroupIDMap.has_key(group):
          print "Group", group, "does not exist but", uid, "is in it"
@@ -412,7 +436,7 @@ def addGroups(existingGroups, newGroups, uid):
          addGroups(existingGroups, SubGroupMap[group], uid)
 
 # Generate the group list
          addGroups(existingGroups, SubGroupMap[group], uid)
 
 # Generate the group list
-def GenGroup(l, File):
+def GenGroup(File):
    grouprevmap = {}
    F = None
    try:
    grouprevmap = {}
    F = None
    try:
@@ -422,6 +446,7 @@ def GenGroup(l, File):
       GroupMap = {}
       for x in GroupIDMap.keys():
          GroupMap[x] = []
       GroupMap = {}
       for x in GroupIDMap.keys():
          GroupMap[x] = []
+      GroupHasPrimaryMembers = {}
      
       # Fetch all the users
       global PasswdAttrs
      
       # Fetch all the users
       global PasswdAttrs
@@ -429,7 +454,9 @@ def GenGroup(l, File):
       # Sort them into a list of groups having a set of users
       for x in PasswdAttrs:
          uid = GetAttr(x, "uid")
       # Sort them into a list of groups having a set of users
       for x in PasswdAttrs:
          uid = GetAttr(x, "uid")
-         if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
+         if 'gidNumber' in x[1]:
+            GroupHasPrimaryMembers[ int(x[1]["gidNumber"][0]) ] = True
+         if x[1].has_key("uidNumber") == 0 or not IsInGroup(x):
             continue
          if x[1].has_key("supplementaryGid") == 0:
             continue
             continue
          if x[1].has_key("supplementaryGid") == 0:
             continue
@@ -442,14 +469,19 @@ def GenGroup(l, File):
       # Output the group file.
       J = 0
       for x in GroupMap.keys():
       # Output the group file.
       J = 0
       for x in GroupMap.keys():
-         grouprevmap[GroupIDMap[x]] = x
          if GroupIDMap.has_key(x) == 0:
             continue
          if GroupIDMap.has_key(x) == 0:
             continue
+
+         if len(GroupMap[x]) == 0 and GroupIDMap[x] not in GroupHasPrimaryMembers:
+            continue
+
+         grouprevmap[GroupIDMap[x]] = x
+
          Line = "%s:x:%u:" % (x, GroupIDMap[x])
          Comma = ''
          for I in GroupMap[x]:
          Line = "%s:x:%u:" % (x, GroupIDMap[x])
          Comma = ''
          for I in GroupMap[x]:
-           Line = Line + ("%s%s" % (Comma, I))
-           Comma = ','
+            Line = Line + ("%s%s" % (Comma, I))
+            Comma = ','
          Line = Sanitize(Line) + "\n"
          F.write("0%u %s" % (J, Line))
          F.write(".%s %s" % (x, Line))
          Line = Sanitize(Line) + "\n"
          F.write("0%u %s" % (J, Line))
          F.write(".%s %s" % (x, Line))
@@ -470,7 +502,7 @@ def CheckForward():
       if x[1].has_key("emailForward") == 0:
          continue
    
       if x[1].has_key("emailForward") == 0:
          continue
    
-      if IsInGroup(x) == 0:
+      if not IsInGroup(x):
          x[1].pop("emailForward")
          continue
 
          x[1].pop("emailForward")
          continue
 
@@ -484,7 +516,7 @@ def CheckForward():
          x[1].pop("emailForward")
 
 # Generate the email forwarding list
          x[1].pop("emailForward")
 
 # Generate the email forwarding list
-def GenForward(l, File):
+def GenForward(File):
    F = None
    try:
       OldMask = os.umask(0022)
    F = None
    try:
       OldMask = os.umask(0022)
@@ -509,27 +541,21 @@ def GenForward(l, File):
       raise
    Done(File, F, None)
 
       raise
    Done(File, F, None)
 
-def GenAllForward(l, File):
+def GenCDB(File, Users, Key):
    Fdb = None
    try:
       OldMask = os.umask(0022)
       Fdb = os.popen("cdbmake %s %s.tmp"%(File, File), "w")
       os.umask(OldMask)
    Fdb = None
    try:
       OldMask = os.umask(0022)
       Fdb = os.popen("cdbmake %s %s.tmp"%(File, File), "w")
       os.umask(OldMask)
-     
-      # Fetch all the users
-      global PasswdAttrs
-     
+
       # Write out the email address for each user
       # Write out the email address for each user
-      for x in PasswdAttrs:
-         if x[1].has_key("emailForward") == 0:
+      for x in Users:
+         if not Key in x[1]:
             continue
             continue
-     
-         # Do not allow people to try to buffer overflow busted parsers
-         Forward = GetAttr(x, "emailForward")
-     
+         Value = GetAttr(x, Key)
          User = GetAttr(x, "uid")
          User = GetAttr(x, "uid")
-         Fdb.write("+%d,%d:%s->%s\n" % (len(User), len(Forward), User, Forward))
-  
+         Fdb.write("+%d,%d:%s->%s\n" % (len(User), len(Value), User, Value))
+
       Fdb.write("\n")
    # Oops, something unspeakable happened.
    except:
       Fdb.write("\n")
    # Oops, something unspeakable happened.
    except:
@@ -539,7 +565,7 @@ def GenAllForward(l, File):
       raise "cdbmake gave an error"
 
 # Generate the anon XEarth marker file
       raise "cdbmake gave an error"
 
 # Generate the anon XEarth marker file
-def GenMarkers(l, File):
+def GenMarkers(File):
    F = None
    try:
       F = open(File + ".tmp", "w")
    F = None
    try:
       F = open(File + ".tmp", "w")
@@ -565,16 +591,16 @@ def GenMarkers(l, File):
    Done(File, F, None)
 
 # Generate the debian-private subscription list
    Done(File, F, None)
 
 # Generate the debian-private subscription list
-def GenPrivate(l, File):
+def GenPrivate(File):
    F = None
    try:
       F = open(File + ".tmp", "w")
      
       # Fetch all the users
    F = None
    try:
       F = open(File + ".tmp", "w")
      
       # Fetch all the users
-      global PasswdAttrs
+      global DebianDDUsers
      
       # Write out the position for each user
      
       # Write out the position for each user
-      for x in PasswdAttrs:
+      for x in DebianDDUsers:
          if x[1].has_key("privateSub") == 0:
             continue
      
          if x[1].has_key("privateSub") == 0:
             continue
      
@@ -582,10 +608,6 @@ def GenPrivate(l, File):
          if x[1].has_key("keyFingerPrint") == 0:
             continue
      
          if x[1].has_key("keyFingerPrint") == 0:
             continue
      
-         # Must be in the Debian group (yuk, hard coded for now)
-         if GetAttr(x, "gidNumber") != "800":
-            continue
-     
          try:
             Line = "%s"%(GetAttr(x, "privateSub"))
             Line = Sanitize(Line) + "\n"
          try:
             Line = "%s"%(GetAttr(x, "privateSub"))
             Line = Sanitize(Line) + "\n"
@@ -600,7 +622,7 @@ def GenPrivate(l, File):
    Done(File, F, None)
 
 # Generate a list of locked accounts
    Done(File, F, None)
 
 # Generate a list of locked accounts
-def GenDisabledAccounts(l, File):
+def GenDisabledAccounts(File):
    F = None
    try:
       F = open(File + ".tmp", "w")
    F = None
    try:
       F = open(File + ".tmp", "w")
@@ -621,11 +643,11 @@ def GenDisabledAccounts(l, File):
          if Pass.find("*LK*") != -1 or Pass.startswith("!"):
             # Format is <login>:<reason>
             Line = "%s:%s" % (GetAttr(x, "uid"), "Account is locked")
          if Pass.find("*LK*") != -1 or Pass.startswith("!"):
             # Format is <login>:<reason>
             Line = "%s:%s" % (GetAttr(x, "uid"), "Account is locked")
+            DisabledUsers.append(x)
      
          if Line != "":
             F.write(Sanitize(Line) + "\n")
      
      
          if Line != "":
             F.write(Sanitize(Line) + "\n")
      
-         DisabledUsers.append(x)
    
    # Oops, something unspeakable happened.
    except:
    
    # Oops, something unspeakable happened.
    except:
@@ -634,7 +656,7 @@ def GenDisabledAccounts(l, File):
    Done(File, F, None)
 
 # Generate the list of local addresses that refuse all mail
    Done(File, F, None)
 
 # Generate the list of local addresses that refuse all mail
-def GenMailDisable(l, File):
+def GenMailDisable(File):
    F = None
    try:
       F = open(File + ".tmp", "w")
    F = None
    try:
       F = open(File + ".tmp", "w")
@@ -650,10 +672,6 @@ def GenMailDisable(l, File):
          else:
             continue
      
          else:
             continue
      
-         # Must be in the Debian group (yuk, hard coded for now)
-         if GetAttr(x, "gidNumber") != "800":
-            continue
-     
          try:
             Line = "%s: %s"%(GetAttr(x, "uid"), Reason)
             Line = Sanitize(Line) + "\n"
          try:
             Line = "%s: %s"%(GetAttr(x, "uid"), Reason)
             Line = Sanitize(Line) + "\n"
@@ -668,7 +686,7 @@ def GenMailDisable(l, File):
    Done(File, F, None)
 
 # Generate a list of uids that should have boolean affects applied
    Done(File, F, None)
 
 # Generate a list of uids that should have boolean affects applied
-def GenMailBool(l, File, Key):
+def GenMailBool(File, Key):
    F = None
    try:
       F = open(File + ".tmp", "w")
    F = None
    try:
       F = open(File + ".tmp", "w")
@@ -682,10 +700,6 @@ def GenMailBool(l, File, Key):
          if x[1].has_key(Key) == 0:
             continue
      
          if x[1].has_key(Key) == 0:
             continue
      
-         # Must be in the Debian group (yuk, hard coded for now)
-         if GetAttr(x, "gidNumber") != "800":
-            continue
-     
          if GetAttr(x, Key) != "TRUE":
             continue
      
          if GetAttr(x, Key) != "TRUE":
             continue
      
@@ -703,7 +717,7 @@ def GenMailBool(l, File, Key):
    Done(File, F, None)
 
 # Generate a list of hosts for RBL or whitelist purposes.
    Done(File, F, None)
 
 # Generate a list of hosts for RBL or whitelist purposes.
-def GenMailList(l, File, Key):
+def GenMailList(File, Key):
    F = None
    try:
       F = open(File + ".tmp", "w")
    F = None
    try:
       F = open(File + ".tmp", "w")
@@ -717,32 +731,28 @@ def GenMailList(l, File, Key):
          if x[1].has_key(Key) == 0:
             continue
      
          if x[1].has_key(Key) == 0:
             continue
      
-         # Must be in the Debian group (yuk, hard coded for now)
-         if GetAttr(x, "gidNumber") != "800":
-            continue
-     
          try:
             found = 0
             Line = None
             for z in x[1][Key]:
                 if Key == "mailWhitelist":
          try:
             found = 0
             Line = None
             for z in x[1][Key]:
                 if Key == "mailWhitelist":
-                    if re.match('^[-\w.]+(/[\d]+)?$', z) == None:
-                        continue
+                   if re.match('^[-\w.]+(/[\d]+)?$', z) == None:
+                      continue
                 else:
                 else:
-                    if re.match('^[-\w.]+$', z) == None:
-                        continue
+                   if re.match('^[-\w.]+$', z) == None:
+                      continue
                 if found == 0:
                 if found == 0:
-                    found = 1
-                    Line = GetAttr(x, "uid")
+                   found = 1
+                   Line = GetAttr(x, "uid")
                 else:
                     Line += " "
                 Line += ": " + z
                 if Key == "mailRHSBL":
                 else:
                     Line += " "
                 Line += ": " + z
                 if Key == "mailRHSBL":
-                    Line += "/$sender_address_domain"
+                   Line += "/$sender_address_domain"
      
             if Line != None:
      
             if Line != None:
-                Line = Sanitize(Line) + "\n"
-                F.write(Line)
+               Line = Sanitize(Line) + "\n"
+               F.write(Line)
          except:
             pass
   
          except:
             pass
   
@@ -763,11 +773,32 @@ def isRoleAccount(pwEntry):
       return False
 
 # Generate the DNS Zone file
       return False
 
 # Generate the DNS Zone file
-def GenDNS(l, File, HomePrefix):
+def GenDNS(File):
    F = None
    try:
       F = open(File + ".tmp", "w")
      
    F = None
    try:
       F = open(File + ".tmp", "w")
      
+#      global HostAttrs
+#
+#      for x in HostAttrs:
+#         if x[1].has_key("hostname") == 0 or \
+#            x[1].has_key("architecture") == 0 or\
+#            x[1].has_key("sshRSAHostKey") == 0:
+#            continue
+#
+#         if IsDebianHost.match(GetAttr(x, "hostname")) is not None:
+#            continue
+#
+#         DNSInfo = ExtractDNSInfo(x)
+#         start = True
+#         for Line in DNSInfo:
+#            if start == True:
+#               Line = "%s.\t%s" % (GetAttr(x, "hostname"), Line)
+#               start = False
+#            else:
+#               Line = "\t\t\t%s" % (Line)
+#            F.write(Line + "\n")
+
       # Fetch all the users
       global PasswdAttrs
      
       # Fetch all the users
       global PasswdAttrs
      
@@ -792,7 +823,7 @@ def GenDNS(l, File, HomePrefix):
      
                   Host = Split[0] + DNSZone
                   if BSMTPCheck.match(Line) != None:
      
                   Host = Split[0] + DNSZone
                   if BSMTPCheck.match(Line) != None:
-                      F.write("; Has BSMTP\n")
+                     F.write("; Has BSMTP\n")
      
                   # Write some identification information
                   if Split[2].lower() == "a":
      
                   # Write some identification information
                   if Split[2].lower() == "a":
@@ -815,35 +846,74 @@ def GenDNS(l, File, HomePrefix):
       raise
    Done(File, F, None)
 
       raise
    Done(File, F, None)
 
-# Generate the DNS SSHFP records
-def GenSSHFP(l, File, HomePrefix):
+def ExtractDNSInfo(x):
+
+   TTLprefix="\t"
+   if 'dnsTTL' in x[1]:
+      TTLprefix="%s\t"%(x[1]["dnsTTL"][0])
+
+   DNSInfo = []
+   if x[1].has_key("ipHostNumber"):
+      for I in x[1]["ipHostNumber"]:
+         if IsV6Addr.match(I) != None:
+            DNSInfo.append("%sIN\tAAAA\t%s" % (TTLprefix, I))
+         else:
+            DNSInfo.append("%sIN\tA\t%s" % (TTLprefix, I))
+
+   Algorithm = None
+
+   if 'sshRSAHostKey' in x[1]:
+      for I in x[1]["sshRSAHostKey"]:
+         Split = I.split()
+         if Split[0] == 'ssh-rsa':
+            Algorithm = 1
+         if Split[0] == 'ssh-dss':
+            Algorithm = 2
+         if Algorithm == None:
+            continue
+         Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
+         DNSInfo.append("%sIN\tSSHFP\t%u 1 %s" % (TTLprefix, Algorithm, Fingerprint))
+
+   if 'architecture' in x[1]:
+      Arch = GetAttr(x, "architecture")
+      Mach = ""
+      if x[1].has_key("machine"):
+         Mach = " " + GetAttr(x, "machine")
+      DNSInfo.append("%sIN\tHINFO\t\"%s%s\" \"%s\"" % (TTLprefix, Arch, Mach, "Debian GNU/Linux"))
+
+   if x[1].has_key("mXRecord"):
+      for I in x[1]["mXRecord"]:
+         DNSInfo.append("%sIN\tMX\t%s" % (TTLprefix, I))
+
+   return DNSInfo
+
+# Generate the DNS records
+def GenZoneRecords(File):
    F = None
    try:
       F = open(File + ".tmp", "w")
    F = None
    try:
       F = open(File + ".tmp", "w")
-     
+
       # Fetch all the hosts
       global HostAttrs
       # Fetch all the hosts
       global HostAttrs
-      if HostAttrs == None:
-         raise UDEmptyList, "No Hosts"
-     
+
       for x in HostAttrs:
       for x in HostAttrs:
-         if x[1].has_key("hostname") == 0 or \
-            x[1].has_key("sshRSAHostKey") == 0:
+         if x[1].has_key("hostname") == 0:
             continue
             continue
-         Host = GetAttr(x, "hostname")
-         Algorithm = None
-         for I in x[1]["sshRSAHostKey"]:
-            Split = I.split()
-            if Split[0] == 'ssh-rsa':
-               Algorithm = 1
-            if Split[0] == 'ssh-dss':
-               Algorithm = 2
-            if Algorithm == None:
-               continue
-            Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
-            Line = "%s. IN SSHFP %u 1 %s" % (Host, Algorithm, Fingerprint)
-            Line = Sanitize(Line) + "\n"
-            F.write(Line)
+
+         if IsDebianHost.match(GetAttr(x, "hostname")) is None:
+            continue
+
+         DNSInfo = ExtractDNSInfo(x)
+         start = True
+         for Line in DNSInfo:
+            if start == True:
+               Line = "%s.\t%s" % (GetAttr(x, "hostname"), Line)
+               start = False
+            else:
+               Line = "\t\t\t%s" % (Line)
+
+            F.write(Line + "\n")
+
    # Oops, something unspeakable happened.
    except:
       Die(File, F, None)
    # Oops, something unspeakable happened.
    except:
       Die(File, F, None)
@@ -851,7 +921,7 @@ def GenSSHFP(l, File, HomePrefix):
    Done(File, F, None)
 
 # Generate the BSMTP file
    Done(File, F, None)
 
 # Generate the BSMTP file
-def GenBSMTP(l, File, HomePrefix):
+def GenBSMTP(File, HomePrefix):
    F = None
    try:
       F = open(File + ".tmp", "w")
    F = None
    try:
       F = open(File + ".tmp", "w")
@@ -891,29 +961,20 @@ def GenBSMTP(l, File, HomePrefix):
       raise
    Done(File, F, None)
   
       raise
    Done(File, F, None)
   
-#  cache IP adresses
-HostToIPCache = {}
-def HostToIP(Host):
-   global HostToIPCache
-   if not Host in HostToIPCache:
-      IPAdressesT = None
-      try:
-         IPAdressesT = list(set([ (a[0], a[4][0]) for a in socket.getaddrinfo(Host, None)]))
-      except socket.gaierror, (code):
-         if code[0] != -2:
-            raise
-      IPAdresses = []
-      if not IPAdressesT is None:
-         for addr in IPAdressesT:
-            if addr[0] == socket.AF_INET:
-               IPAdresses += [addr[1], "::ffff:"+addr[1]]
-            else:
-               IPAdresses += [addr[1]]
-      HostToIPCache[Host] = IPAdresses
-   return HostToIPCache[Host]
+def HostToIP(Host, mapped=True):
+
+   IPAdresses = []
+
+   if Host[1].has_key("ipHostNumber"):
+      for addr in Host[1]["ipHostNumber"]:
+         IPAdresses.append(addr)
+         if IsV6Addr.match(addr) is None and mapped == "True":
+            IPAdresses.append("::ffff:"+addr)
+
+   return IPAdresses
 
 # Generate the ssh known hosts file
 
 # Generate the ssh known hosts file
-def GenSSHKnown(l, File, mode=None):
+def GenSSHKnown(File, mode=None):
    F = None
    try:
       OldMask = os.umask(0022)
    F = None
    try:
       OldMask = os.umask(0022)
@@ -921,8 +982,6 @@ def GenSSHKnown(l, File, mode=None):
       os.umask(OldMask)
      
       global HostAttrs
       os.umask(OldMask)
      
       global HostAttrs
-      if HostAttrs == None:
-         raise UDEmptyList, "No Hosts"
      
       for x in HostAttrs:
          if x[1].has_key("hostname") == 0 or \
      
       for x in HostAttrs:
          if x[1].has_key("hostname") == 0 or \
@@ -954,10 +1013,13 @@ def GenSSHKnown(l, File, mode=None):
      
          for I in x[1]["sshRSAHostKey"]:
             if mode and mode == 'authorized_keys':
      
          for I in x[1]["sshRSAHostKey"]:
             if mode and mode == 'authorized_keys':
-               #Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,from="%s" %s' % (Host, ",".join(HNames + HostToIP(Host)), I)
-               Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
+               hosts = HostToIP(x)
+               if 'sshdistAuthKeysHost' in x[1]:
+                  hosts += x[1]['sshdistAuthKeysHost']
+               Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,from="%s" %s' % (Host, ",".join(hosts), I)
+               #Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
             else:
             else:
-               Line = "%s %s" %(",".join(HostNames + HostToIP(Host)), I)
+               Line = "%s %s" %(",".join(HostNames + HostToIP(x, False)), I)
             Line = Sanitize(Line) + "\n"
             F.write(Line)
    # Oops, something unspeakable happened.
             Line = Sanitize(Line) + "\n"
             F.write(Line)
    # Oops, something unspeakable happened.
@@ -967,51 +1029,42 @@ def GenSSHKnown(l, File, mode=None):
    Done(File, F, None)
 
 # Generate the debianhosts file (list of all IP addresses)
    Done(File, F, None)
 
 # Generate the debianhosts file (list of all IP addresses)
-def GenHosts(l, File):
+def GenHosts(File):
    F = None
    try:
       OldMask = os.umask(0022)
       F = open(File + ".tmp", "w", 0644)
       os.umask(OldMask)
      
    F = None
    try:
       OldMask = os.umask(0022)
       F = open(File + ".tmp", "w", 0644)
       os.umask(OldMask)
      
-      # Fetch all the hosts
-      hostnames = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "hostname=*",
-                             ["hostname"])
-     
-      if hostnames == None:
-         raise UDEmptyList, "No Hosts"
-     
       seen = set()
       seen = set()
-      for x in hostnames:
-         host = GetAttr(x, "hostname", None)
-         if host:
-            addrs = []
-            try:
-               addrs += socket.getaddrinfo(host, None, socket.AF_INET)
-            except socket.error:
-               pass
-            try:
-               addrs += socket.getaddrinfo(host, None, socket.AF_INET6)
-            except socket.error:
-               pass
-           
-            for addrinfo in addrs:
-               if addrinfo[0] in (socket.AF_INET, socket.AF_INET6):
-                  addr = addrinfo[4][0]
-                  if addr not in seen:
-                     print >> F, addrinfo[4][0]
-                     seen.add(addr)
+
+      global HostAttrs
+
+      for x in HostAttrs:
+
+         if IsDebianHost.match(GetAttr(x, "hostname")) is None:
+            continue
+
+         if not 'ipHostNumber' in x[1]:
+            continue
+
+         addrs = x[1]["ipHostNumber"]
+         for addr in addrs:
+            if addr not in seen:
+               seen.add(addr)
+               addr = Sanitize(addr) + "\n"
+               F.write(addr)
+
    # Oops, something unspeakable happened.
    except:
    # Oops, something unspeakable happened.
    except:
-     Die(File, F, None)
-     raise
+      Die(File, F, None)
+      raise
    Done(File, F, None)
 
    Done(File, F, None)
 
-def GenKeyrings(l, OutDir):
+def GenKeyrings(OutDir):
    for k in Keyrings:
       shutil.copy(k, OutDir)
 
    for k in Keyrings:
       shutil.copy(k, OutDir)
 
-
 # Connect to the ldap server
 l = connectLDAP()
 F = open(PassDir + "/pass-" + pwd.getpwuid(os.getuid())[0], "r")
 # Connect to the ldap server
 l = connectLDAP()
 F = open(PassDir + "/pass-" + pwd.getpwuid(os.getuid())[0], "r")
@@ -1026,6 +1079,8 @@ Attrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "gid=*",\
 
 # Generate the SubGroupMap and GroupIDMap
 for x in Attrs:
 
 # Generate the SubGroupMap and GroupIDMap
 for x in Attrs:
+   if x[1].has_key("accountStatus") and x[1]['accountStatus'] == "disabled":
+      continue
    if x[1].has_key("gidNumber") == 0:
       continue
    GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0])
    if x[1].has_key("gidNumber") == 0:
       continue
    GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0])
@@ -1041,65 +1096,61 @@ PasswdAttrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "uid=*",\
                  "allowedHost", "sshRSAAuthKey", "dnsZoneEntry", "cn", "sn",\
                  "keyFingerPrint", "privateSub", "mailDisableMessage",\
                  "mailGreylisting", "mailCallout", "mailRBL", "mailRHSBL",\
                  "allowedHost", "sshRSAAuthKey", "dnsZoneEntry", "cn", "sn",\
                  "keyFingerPrint", "privateSub", "mailDisableMessage",\
                  "mailGreylisting", "mailCallout", "mailRBL", "mailRHSBL",\
-                 "mailWhitelist", "sudoPassword", "objectClass", "accountStatus"])
+                 "mailWhitelist", "sudoPassword", "objectClass", "accountStatus",\
+                 "mailContentInspectionAction"])
 
 if PasswdAttrs is None:
    raise UDEmptyList, "No Users"
 
 
 if PasswdAttrs is None:
    raise UDEmptyList, "No Users"
 
+PasswdAttrs.sort(lambda x, y: cmp((GetAttr(x, "uid")).lower(), (GetAttr(y, "uid")).lower()))
+
 # Fetch all the hosts
 # Fetch all the hosts
-HostAttrs    = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "sshRSAHostKey=*",\
-                ["hostname", "sshRSAHostKey", "purpose"])
+HostAttrs    = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "objectClass=debianServer",\
+                ["hostname", "sshRSAHostKey", "purpose", "allowedGroups", "exportOptions",\
+                 "mXRecord", "ipHostNumber", "dnsTTL", "machine", "architecture"])
 
 
-# Open the control file
-if len(sys.argv) == 1:
-   F = open(GenerateConf, "r")
-else:
-   F = open(sys.argv[1], "r")
+if HostAttrs == None:
+   raise UDEmptyList, "No Hosts"
+
+HostAttrs.sort(lambda x, y: cmp((GetAttr(x, "hostname")).lower(), (GetAttr(y, "hostname")).lower()))
 
 # Generate global things
 GlobalDir = GenerateDir + "/"
 
 # Generate global things
 GlobalDir = GenerateDir + "/"
-GenMailDisable(l, GlobalDir + "mail-disable")
-
-for x in PasswdAttrs:
-   if IsRetired(x):
-      RetiredUsers.append(x)
+GenDisabledAccounts(GlobalDir + "disabled-accounts")
 
 
-PasswdAttrs = filter(lambda x: not x in RetiredUsers, PasswdAttrs)
+PasswdAttrs = filter(lambda x: not IsRetired(x), PasswdAttrs)
+DebianDDUsers = filter(lambda x: IsGidDebian(x), PasswdAttrs)
 
 CheckForward()
 
 
 CheckForward()
 
-SSHFiles = GenSSHShadow(l)
-GenAllForward(l, GlobalDir + "mail-forward.cdb")
-GenMarkers(l, GlobalDir + "markers")
-GenPrivate(l, GlobalDir + "debian-private")
-GenDisabledAccounts(l, GlobalDir + "disabled-accounts")
-GenSSHKnown(l, GlobalDir + "ssh_known_hosts")
-#GenSSHKnown(l,GlobalDir+"authorized_keys", 'authorized_keys')
-GenHosts(l, GlobalDir + "debianhosts")
-GenMailBool(l, GlobalDir + "mail-greylist", "mailGreylisting")
-GenMailBool(l, GlobalDir + "mail-callout", "mailCallout")
-GenMailList(l, GlobalDir + "mail-rbl", "mailRBL")
-GenMailList(l, GlobalDir + "mail-rhsbl", "mailRHSBL")
-GenMailList(l, GlobalDir + "mail-whitelist", "mailWhitelist")
-GenKeyrings(l, GlobalDir)
+GenMailDisable(GlobalDir + "mail-disable")
+GenCDB(GlobalDir + "mail-forward.cdb", PasswdAttrs, 'emailForward')
+GenCDB(GlobalDir + "mail-contentinspectionaction.cdb", PasswdAttrs, 'mailContentInspectionAction')
+GenPrivate(GlobalDir + "debian-private")
+GenSSHKnown(GlobalDir+"authorized_keys", 'authorized_keys')
+GenMailBool(GlobalDir + "mail-greylist", "mailGreylisting")
+GenMailBool(GlobalDir + "mail-callout", "mailCallout")
+GenMailList(GlobalDir + "mail-rbl", "mailRBL")
+GenMailList(GlobalDir + "mail-rhsbl", "mailRHSBL")
+GenMailList(GlobalDir + "mail-whitelist", "mailWhitelist")
+GenKeyrings(GlobalDir)
 
 # Compatibility.
 
 # Compatibility.
-GenForward(l, GlobalDir + "forward-alias")
+GenForward(GlobalDir + "forward-alias")
 
 PasswdAttrs = filter(lambda x: not x in DisabledUsers, PasswdAttrs)
 
 
 PasswdAttrs = filter(lambda x: not x in DisabledUsers, PasswdAttrs)
 
-while(1):
-   Line = F.readline()
-   if Line == "":
-      break
-   Line = Line.strip()
-   if Line == "":
-      continue
-   if Line[0] == '#':
+SSHFiles = GenSSHShadow()
+GenMarkers(GlobalDir + "markers")
+GenSSHKnown(GlobalDir + "ssh_known_hosts")
+GenHosts(GlobalDir + "debianhosts")
+
+for host in HostAttrs:
+   if not "hostname" in host[1]:
       continue
 
       continue
 
-   Split = Line.split(" ")
-   OutDir = GenerateDir + '/' + Split[0] + '/'
+   CurrentHost = host[1]['hostname'][0]
+   OutDir = GenerateDir + '/' + CurrentHost + '/'
    try:
       os.mkdir(OutDir)
    except: 
    try:
       os.mkdir(OutDir)
    except: 
@@ -1107,68 +1158,76 @@ while(1):
 
    # Get the group list and convert any named groups to numerics
    GroupList = {}
 
    # Get the group list and convert any named groups to numerics
    GroupList = {}
+   for groupname in AllowedGroupsPreload.strip().split(" "):
+      GroupList[groupname] = True
+   if 'allowedGroups' in host[1]:
+      for groupname in host[1]['allowedGroups']:
+         GroupList[groupname] = True
+   for groupname in GroupList.keys():
+      if groupname in GroupIDMap:
+         GroupList[str(GroupIDMap[groupname])] = True
+
    ExtraList = {}
    ExtraList = {}
-   for I in Split[2:]:
-      if I[0] == '[':
-         ExtraList[I] = None
-         continue
-      GroupList[I] = None
-      if GroupIDMap.has_key(I):
-         GroupList[str(GroupIDMap[I])] = None
+   if 'exportOptions' in host[1]:
+      for extra in host[1]['exportOptions']:
+         ExtraList[extra.upper()] = True
 
    Allowed = GroupList
    if Allowed == {}:
 
    Allowed = GroupList
    if Allowed == {}:
-     Allowed = None
-   CurrentHost = Split[0]
+      Allowed = None
 
    DoLink(GlobalDir, OutDir, "debianhosts")
    DoLink(GlobalDir, OutDir, "ssh_known_hosts")
    DoLink(GlobalDir, OutDir, "disabled-accounts")
 
    sys.stdout.flush()
 
    DoLink(GlobalDir, OutDir, "debianhosts")
    DoLink(GlobalDir, OutDir, "ssh_known_hosts")
    DoLink(GlobalDir, OutDir, "disabled-accounts")
 
    sys.stdout.flush()
-   if ExtraList.has_key("[NOPASSWD]"):
-      userlist = GenPasswd(l, OutDir + "passwd", Split[1], "*")
+   if 'NOPASSWD' in ExtraList:
+      userlist = GenPasswd(OutDir + "passwd", HomePrefix, "*")
    else:
    else:
-      userlist = GenPasswd(l, OutDir + "passwd", Split[1], "x")
+      userlist = GenPasswd(OutDir + "passwd", HomePrefix, "x")
    sys.stdout.flush()
    sys.stdout.flush()
-   grouprevmap = GenGroup(l, OutDir + "group")
-   GenShadowSudo(l, OutDir + "sudo-passwd", ExtraList.has_key("[UNTRUSTED]") or ExtraList.has_key("[NOPASSWD]"))
+   grouprevmap = GenGroup(OutDir + "group")
+   GenShadowSudo(OutDir + "sudo-passwd", ('UNTRUSTED' in ExtraList) or ('NOPASSWD' in ExtraList))
 
    # Now we know who we're allowing on the machine, export
    # the relevant ssh keys
    GenSSHtarballs(userlist, SSHFiles, grouprevmap, os.path.join(OutDir, 'ssh-keys.tar.gz'))
 
 
    # Now we know who we're allowing on the machine, export
    # the relevant ssh keys
    GenSSHtarballs(userlist, SSHFiles, grouprevmap, os.path.join(OutDir, 'ssh-keys.tar.gz'))
 
-   if ExtraList.has_key("[UNTRUSTED]"):
-      print "[UNTRUSTED] tag is obsolete and may be removed in the future."
-      continue
-   if not ExtraList.has_key("[NOPASSWD]"):
-      GenShadow(l, OutDir + "shadow")
+   if not 'NOPASSWD' in ExtraList:
+      GenShadow(OutDir + "shadow")
 
    # Link in global things
 
    # Link in global things
-   if not ExtraList.has_key("[NOMARKERS]"):
+   if not 'NOMARKERS' in ExtraList:
       DoLink(GlobalDir, OutDir, "markers")
    DoLink(GlobalDir, OutDir, "mail-forward.cdb")
       DoLink(GlobalDir, OutDir, "markers")
    DoLink(GlobalDir, OutDir, "mail-forward.cdb")
+   DoLink(GlobalDir, OutDir, "mail-contentinspectionaction.cdb")
    DoLink(GlobalDir, OutDir, "mail-disable")
    DoLink(GlobalDir, OutDir, "mail-greylist")
    DoLink(GlobalDir, OutDir, "mail-callout")
    DoLink(GlobalDir, OutDir, "mail-rbl")
    DoLink(GlobalDir, OutDir, "mail-rhsbl")
    DoLink(GlobalDir, OutDir, "mail-whitelist")
    DoLink(GlobalDir, OutDir, "mail-disable")
    DoLink(GlobalDir, OutDir, "mail-greylist")
    DoLink(GlobalDir, OutDir, "mail-callout")
    DoLink(GlobalDir, OutDir, "mail-rbl")
    DoLink(GlobalDir, OutDir, "mail-rhsbl")
    DoLink(GlobalDir, OutDir, "mail-whitelist")
+   GenCDB(OutDir + "user-forward.cdb", filter(lambda x: IsInGroup(x), PasswdAttrs), 'emailForward')
+   GenCDB(OutDir + "batv-tokens.cdb", filter(lambda x: IsInGroup(x), PasswdAttrs), 'bATVToken')
+   GenCDB(OutDir + "default-mail-options.cdb", filter(lambda x: IsInGroup(x), PasswdAttrs), 'mailDefaultOptions')
 
    # Compatibility.
    DoLink(GlobalDir, OutDir, "forward-alias")
 
 
    # Compatibility.
    DoLink(GlobalDir, OutDir, "forward-alias")
 
-   if ExtraList.has_key("[DNS]"):
-      GenDNS(l, OutDir + "dns-zone", Split[1])
-      GenSSHFP(l, OutDir + "dns-sshfp", Split[1])
+   if 'DNS' in ExtraList:
+      GenDNS(OutDir + "dns-zone")
+      GenZoneRecords(OutDir + "dns-sshfp")
+
+   if 'AUTHKEYS' in ExtraList:
+      DoLink(GlobalDir, OutDir, "authorized_keys")
 
 
-   if ExtraList.has_key("[BSMTP]"):
-      GenBSMTP(l, OutDir + "bsmtp", Split[1])
+   if 'BSMTP' in ExtraList:
+      GenBSMTP(OutDir + "bsmtp", HomePrefix)
 
 
-   if ExtraList.has_key("[PRIVATE]"):
+   if 'PRIVATE' in ExtraList:
       DoLink(GlobalDir, OutDir, "debian-private")
 
       DoLink(GlobalDir, OutDir, "debian-private")
 
-   if ExtraList.has_key("[KEYRING]"):
+   if 'KEYRING' in ExtraList:
       for k in Keyrings:
         DoLink(GlobalDir, OutDir, os.path.basename(k))
    else:
       for k in Keyrings:
         DoLink(GlobalDir, OutDir, os.path.basename(k))
    else: