#!/usr/bin/env python3
import argparse
import fnmatch
import getopt
import os
import socket
import sys

def getfqdn(host=None):
    host = host or socket.gethostname()
    try:
        ai = socket.getaddrinfo(host, None, 0, 0, 0, socket.AI_CANONNAME)
        return ai[0][3] if ai else host
    except:
        return host

def read_rules(rules_file):
    defprinc = None
    principals = []
    rules = {}
    rgroups = {}
    isgroup = False
    lineno = 0
    for line in open(rules_file, "r"):
        lineno += 1
        line = line.rstrip()
        if not line or line.startswith("#"):
            continue

        if line[0].isspace():
            masks = line.split()
        elif line[0] == "+":
            isgroup = True
            line = line.split()
            defprinc = line[0]
            masks = line[1:]
        else:
            isgroup = False
            line = line.split()
            defprinc = line[0]
            masks = line[1:]

        if not defprinc:
            print("warning: missing principal on line %d\n" % lineno, file=sys.stderr)
            continue

        if isgroup:
            if defprinc not in rgroups:
                rgroups[defprinc] = set()
            rgroups[defprinc] |= set(masks)
        else:
            if defprinc not in rules:
                principals.append(defprinc)
                rules[defprinc] = set()
            rules[defprinc] |= set(masks)

    for rgroup in list(rgroups):
        ngroup = "!"+rgroup
        rgroups[ngroup] = set("!"+r for r in rgroups[rgroup])

    for princ in rules:
        for rgroup in rgroups:
            if rgroup in rules[princ]:
                rules[princ].remove(rgroup)
                rules[princ] |= rgroups[rgroup]

    return principals, rules

def test_mask(fqdn, mask):
    if mask.startswith("!"):
        return not fnmatch.fnmatch(fqdn, mask[1:])
    else:
        return fnmatch.fnmatch(fqdn, mask)

def test_rule(fqdn, masks):
    blacklist = [m[1:] for m in masks if m.startswith("!")]
    whitelist = [m for m in masks if not m.startswith("!")]

    func = lambda mask: test_mask(fqdn, mask)
    ok = True
    if blacklist:
        ok = ok and not any(map(func, blacklist))
    if whitelist:
        ok = ok and any(map(func, whitelist))
    return ok

fqdn = getfqdn()

rules_file = os.path.expanduser("~/.config/nullroute.eu.org/k5login.rules")
if not os.path.exists(rules_file):
    rules_file = os.path.expanduser("~/.dotfiles/k5login.rules")
if not os.path.exists(rules_file):
    rules_file = os.path.expanduser("~/lib/dotfiles/k5login.rules")

k5login_file = os.path.expanduser("~/.k5login")

parser = argparse.ArgumentParser()
parser.add_argument("-F", "--fqdn",
                    help="produce output for a different host FQDN")
parser.add_argument("-i", "--rules-file",
                    help="path to input rules file")
parser.add_argument("-o", "--k5login-file",
                    help="path to output .k5login file")
args = parser.parse_args()

if args.fqdn:
    fqdn = args.fqdn
if args.rules_file:
    rules_file = args.rules_file

if args.k5login_file:
    k5login_file = args.k5login_file

principals, rules = read_rules(rules_file)

with open(k5login_file, "w") as outfd:
    for princ in principals:
        masks = rules[princ]
        if test_rule(fqdn, masks):
            outfd.write(princ+"\n")
