135 lines
3.9 KiB
Python
Executable file
135 lines
3.9 KiB
Python
Executable file
#!/usr/bin/python3
|
|
|
|
import sys
|
|
import argparse
|
|
from time import time
|
|
from struct import pack
|
|
|
|
import ldap3
|
|
|
|
|
|
def ldap_connect():
|
|
server = ldap3.Server("ldapi:///var/run/ldapi")
|
|
conn = ldap3.Connection(
|
|
server,
|
|
authentication=ldap3.SASL,
|
|
sasl_mechanism=ldap3.EXTERNAL,
|
|
sasl_credentials="",
|
|
client_strategy=ldap3.SYNC,
|
|
)
|
|
conn.bind()
|
|
conn.search(
|
|
search_base="",
|
|
search_filter="(objectClass=*)",
|
|
search_scope=ldap3.BASE,
|
|
attributes=["namingContexts"],
|
|
)
|
|
basedn = conn.response[0]["attributes"]["namingContexts"][0]
|
|
return (conn, basedn)
|
|
|
|
|
|
def get_last_modified(principal):
|
|
""" create krbExtraData value with KRB5_TL_MOD_PRINC type """
|
|
data = pack(
|
|
"<ccL%dsc" % len(principal),
|
|
b"\x00",
|
|
b"\x02",
|
|
int(time()),
|
|
bytes(principal, "UTF-8"),
|
|
b"\x00",
|
|
)
|
|
return data
|
|
|
|
|
|
def get_kvno():
|
|
""" return krbExtraData value with KRB_TL_MKVNO type with value 0 """
|
|
return pack("<cccc", b"\x00", b"\x08", b"\x01", b"\x00")
|
|
|
|
|
|
def principal_create(args, conn, basedn):
|
|
if not args.container:
|
|
(principal, realm) = args.principal.split("@", 2)
|
|
(service, hostname) = principal.split("/", 2)
|
|
conn.search(
|
|
search_base=basedn,
|
|
search_filter=f"(&(cn={hostname})(objectClass=device))",
|
|
)
|
|
if len(conn.response) != 1:
|
|
print(
|
|
"ERROR: Could not get container dn for principal '{args.principal}'",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
args.container = conn.response[0]["dn"]
|
|
conn.add(
|
|
f"krbPrincipalName={args.principal},{args.container}",
|
|
attributes={
|
|
"objectClass": [
|
|
"krbPrincipal",
|
|
"krbPrincipalAux",
|
|
"krbTicketPolicyAux",
|
|
],
|
|
"krbPrincipalName": args.principal,
|
|
"krbExtraData": [get_last_modified("root/admin@FOO.SH"), get_kvno()],
|
|
},
|
|
)
|
|
if conn.result["result"] != 0:
|
|
print(
|
|
f"ERROR: Failed to add principal: {conn.result['description']}",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
|
|
def principal_delete(args, conn, basedn):
|
|
conn.search(
|
|
search_base=basedn,
|
|
search_filter=f"(&(krbPrincipalName={args.principal})(objectClass=krbPrincipalAux))",
|
|
attributes=[],
|
|
)
|
|
if len(conn.response) != 1:
|
|
print(f"ERROR: Could not find principal '{args.principal}'", file=sys.stderr)
|
|
sys.exit(1)
|
|
conn.delete(conn.response[0]["dn"])
|
|
if conn.result["result"] != 0:
|
|
print(
|
|
f"ERROR: Failed to delete principal: {conn.result['description']}",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
|
|
def principal_list(args, conn, baesdn):
|
|
conn.search(
|
|
search_base=basedn,
|
|
search_filter="(objectClass=krbPrincipalAux)",
|
|
attributes=["krbPrincipalName"],
|
|
)
|
|
for result in conn.response:
|
|
for name in result["attributes"]["krbPrincipalName"]:
|
|
print(name)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers()
|
|
|
|
create = subparsers.add_parser("add")
|
|
create.set_defaults(func=principal_create)
|
|
create.add_argument("--principal", metavar="PRINCIPAL", type=str, required=True)
|
|
create.add_argument("--container", metavar="CONTAINER", type=str, required=False)
|
|
|
|
delete = subparsers.add_parser("del")
|
|
delete.set_defaults(func=principal_delete)
|
|
delete.add_argument("--principal", metavar="PRINCIPAL", type=str, required=True)
|
|
|
|
show = subparsers.add_parser("list")
|
|
show.set_defaults(func=principal_list)
|
|
parser.set_defaults(func=principal_list)
|
|
|
|
args = parser.parse_args()
|
|
try:
|
|
(conn, basedn) = ldap_connect()
|
|
args.func(args, conn, basedn)
|
|
except KeyboardInterrupt:
|
|
sys.exit(1)
|