+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+# Generate a list of locked accounts
+def GenDisabledAccounts(File):
+ F = None
+ try:
+ F = open(File + ".tmp", "w")
+
+ # Fetch all the users
+ global PasswdAttrs
+ global DisabledUsers
+
+ I = 0
+ for x in PasswdAttrs:
+ if x[1].has_key("uidNumber") == 0:
+ continue
+
+ Pass = GetAttr(x, "userPassword")
+ Line = ""
+ # *LK* is the reference value for a locked account
+ # password starting with ! is also a locked account
+ 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")
+
+
+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+# Generate the list of local addresses that refuse all mail
+def GenMailDisable(File):
+ F = None
+ try:
+ F = open(File + ".tmp", "w")
+
+ # Fetch all the users
+ global PasswdAttrs
+
+ for x in PasswdAttrs:
+ Reason = None
+
+ if x[1].has_key("mailDisableMessage"):
+ Reason = GetAttr(x, "mailDisableMessage")
+ else:
+ continue
+
+ try:
+ Line = "%s: %s"%(GetAttr(x, "uid"), Reason)
+ Line = Sanitize(Line) + "\n"
+ F.write(Line)
+ except:
+ pass
+
+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+# Generate a list of uids that should have boolean affects applied
+def GenMailBool(File, Key):
+ F = None
+ try:
+ F = open(File + ".tmp", "w")
+
+ # Fetch all the users
+ global PasswdAttrs
+
+ for x in PasswdAttrs:
+ Reason = None
+
+ if x[1].has_key(Key) == 0:
+ continue
+
+ if GetAttr(x, Key) != "TRUE":
+ continue
+
+ try:
+ Line = "%s"%(GetAttr(x, "uid"))
+ Line = Sanitize(Line) + "\n"
+ F.write(Line)
+ except:
+ pass
+
+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+# Generate a list of hosts for RBL or whitelist purposes.
+def GenMailList(File, Key):
+ F = None
+ try:
+ F = open(File + ".tmp", "w")
+
+ # Fetch all the users
+ global PasswdAttrs
+
+ for x in PasswdAttrs:
+ Reason = None
+
+ if x[1].has_key(Key) == 0:
+ continue
+
+ try:
+ found = 0
+ Line = None
+ for z in x[1][Key]:
+ if Key == "mailWhitelist":
+ if re.match('^[-\w.]+(/[\d]+)?$', z) == None:
+ continue
+ else:
+ if re.match('^[-\w.]+$', z) == None:
+ continue
+ if found == 0:
+ found = 1
+ Line = GetAttr(x, "uid")
+ else:
+ Line += " "
+ Line += ": " + z
+ if Key == "mailRHSBL":
+ Line += "/$sender_address_domain"
+
+ if Line != None:
+ Line = Sanitize(Line) + "\n"
+ F.write(Line)
+ except:
+ pass
+
+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+def isRoleAccount(pwEntry):
+ if not pwEntry.has_key("objectClass"):
+ raise "pwEntry has no objectClass"
+ oc = pwEntry['objectClass']
+ try:
+ i = oc.index('debianRoleAccount')
+ return True
+ except ValueError:
+ return False
+
+# Generate the DNS Zone file
+def GenDNS(File):
+ F = None
+ try:
+ F = open(File + ".tmp", "w")
+
+ # Fetch all the users
+ global PasswdAttrs
+ RRs = {}
+
+ # Write out the zone file entry for each user
+ for x in PasswdAttrs:
+ if x[1].has_key("dnsZoneEntry") == 0:
+ continue
+
+ # If the account has no PGP key, do not write it
+ if x[1].has_key("keyFingerPrint") == 0 and not isRoleAccount(x[1]):
+ continue
+ try:
+ F.write("; %s\n"%(EmailAddress(x)))
+ for z in x[1]["dnsZoneEntry"]:
+ Split = z.lower().split()
+ if Split[1].lower() == 'in':
+ for y in range(0, len(Split)):
+ if Split[y] == "$":
+ Split[y] = "\n\t"
+ Line = " ".join(Split) + "\n"
+ F.write(Line)
+
+ Host = Split[0] + DNSZone
+ if BSMTPCheck.match(Line) != None:
+ F.write("; Has BSMTP\n")
+
+ # Write some identification information
+ if not RRs.has_key(Host):
+ if Split[2].lower() in ["a", "aaaa"]:
+ Line = "%s IN TXT \"%s\"\n"%(Split[0], EmailAddress(x))
+ for y in x[1]["keyFingerPrint"]:
+ Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0], FormatPGPKey(y))
+ F.write(Line)
+ RRs[Host] = 1
+ else:
+ Line = "; Err %s"%(str(Split))
+ F.write(Line)
+
+ F.write("\n")
+ except:
+ F.write("; Errors\n")
+ pass
+
+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+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")
+
+ # Fetch all the hosts
+ global HostAttrs
+
+ for x in HostAttrs:
+ if x[1].has_key("hostname") == 0:
+ continue
+
+ 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")
+
+ # this would write sshfp lines for services on machines
+ # but we can't yet, since some are cnames and we'll make
+ # an invalid zonefile
+ #
+ # for i in x[1].get("purpose", []):
+ # m = PurposeHostField.match(i)
+ # if m:
+ # m = m.group(1)
+ # # we ignore [[*..]] entries
+ # if m.startswith('*'):
+ # continue
+ # if m.startswith('-'):
+ # m = m[1:]
+ # if m:
+ # if not m.endswith(HostDomain):
+ # continue
+ # if not m.endswith('.'):
+ # m = m + "."
+ # for Line in DNSInfo:
+ # if isSSHFP.match(Line):
+ # Line = "%s\t%s" % (m, Line)
+ # F.write(Line + "\n")
+
+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+# Generate the BSMTP file
+def GenBSMTP(File, HomePrefix):
+ F = None
+ try:
+ F = open(File + ".tmp", "w")
+
+ # Fetch all the users
+ global PasswdAttrs
+
+ # Write out the zone file entry for each user
+ for x in PasswdAttrs:
+ if x[1].has_key("dnsZoneEntry") == 0:
+ continue
+
+ # If the account has no PGP key, do not write it
+ if x[1].has_key("keyFingerPrint") == 0:
+ continue
+ try:
+ for z in x[1]["dnsZoneEntry"]:
+ Split = z.lower().split()
+ if Split[1].lower() == 'in':
+ for y in range(0, len(Split)):
+ if Split[y] == "$":
+ Split[y] = "\n\t"
+ Line = " ".join(Split) + "\n"
+
+ Host = Split[0] + DNSZone
+ if BSMTPCheck.match(Line) != None:
+ F.write("%s: user=%s group=Debian file=%s%s/bsmtp/%s\n"%(Host,
+ GetAttr(x, "uid"), HomePrefix, GetAttr(x, "uid"), Host))
+
+ except:
+ F.write("; Errors\n")
+ pass
+
+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+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
+def GenSSHKnown(File, mode=None):
+ F = None
+ try:
+ OldMask = os.umask(0022)
+ F = open(File + ".tmp", "w", 0644)
+ os.umask(OldMask)
+
+ global HostAttrs
+
+ for x in HostAttrs:
+ if x[1].has_key("hostname") == 0 or \
+ x[1].has_key("sshRSAHostKey") == 0:
+ continue
+ Host = GetAttr(x, "hostname")
+ HostNames = [ Host ]
+ if Host.endswith(HostDomain):
+ HostNames.append(Host[:-(len(HostDomain) + 1)])
+
+ # in the purpose field [[host|some other text]] (where some other text is optional)
+ # makes a hyperlink on the web thing. we now also add these hosts to the ssh known_hosts
+ # file. But so that we don't have to add everything we link we can add an asterisk
+ # and say [[*... to ignore it. In order to be able to add stuff to ssh without
+ # http linking it we also support [[-hostname]] entries.
+ for i in x[1].get("purpose", []):
+ m = PurposeHostField.match(i)
+ if m:
+ m = m.group(1)
+ # we ignore [[*..]] entries
+ if m.startswith('*'):
+ continue
+ if m.startswith('-'):
+ m = m[1:]
+ if m:
+ HostNames.append(m)
+ if m.endswith(HostDomain):
+ HostNames.append(m[:-(len(HostDomain) + 1)])
+
+ for I in x[1]["sshRSAHostKey"]:
+ if mode and mode == 'authorized_keys':
+ 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)
+ else:
+ Line = "%s %s" %(",".join(HostNames + HostToIP(x, False)), I)
+ Line = Sanitize(Line) + "\n"
+ F.write(Line)
+ # Oops, something unspeakable happened.
+ except:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+# Generate the debianhosts file (list of all IP addresses)
+def GenHosts(File):
+ F = None
+ try:
+ OldMask = os.umask(0022)
+ F = open(File + ".tmp", "w", 0644)
+ os.umask(OldMask)
+
+ seen = set()
+
+ 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:
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
+
+def GenKeyrings(OutDir):
+ for k in Keyrings:
+ shutil.copy(k, OutDir)
+