#!/usr/bin/env python3

import sys

sys.path.insert(0, "bin/python")

import os
import argparse
import struct

from samba.ndr import ndr_unpack, ndr_print
from samba.dcerpc import smbXsrv
from samba.dcerpc import server_id
import tdb

def print_watchers(num_watched, blob):
    for i in range(0,num_watched):
        id = ndr_unpack(server_id.server_id, blob[:24])
        print(ndr_print(id))
        blob = blob[24:]

def print_record(data, ndr_type, watched, ctdb):
    blob = data

    if ctdb:
        (rsn, dmaster, reserved1, flags) = struct.unpack('QIII', bytes(blob[:20]))
        blob = blob[24:]
        print("    ctdb record header: rsn=%lu, dmaster=%u, reserved1=0x%x, flags=0x%x len=%u" %
              (rsn, dmaster, reserved1, flags, len(blob)))
        if len(blob) == 0:
            return

    if watched:
        (num_watched, ) = struct.unpack('I', bytes(blob[:4]))
        blob = blob[4:]

        deleted_bit = 1<<31
        deleted = num_watched & deleted_bit

        num_watched = num_watched & ~deleted_bit
        if num_watched > 0:
            if deleted:
                deleted_str = "yes"
            else:
                deleted_str = "no"
            print("    num_watched: %d, deleted: %s" % (num_watched, deleted_str))
            print_watchers(num_watched, blob)
            blob = blob[num_watched*4:]

    try:
        unpacked = ndr_unpack(ndr_type, blob, allow_remaining=True)
    except Exception:
        unpacked = None
        pass
    if unpacked is not None:
        print(ndr_print(unpacked))
    else:
        print("<failed to parse>")

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('path', help='Path to the TDB file')
    parser.add_argument('-c', '--ctdb',
                        default=False,
                        action="store_true",
                        help='The TDB database is from a ctdb cluster')
    args = parser.parse_args()

    watched = False
    if 'smbXsrv_session' in args.path:
        ndr_type = smbXsrv.session_globalB
        watched = True
    elif 'smbXsrv_open' in args.path:
        ndr_type = smbXsrv.open_globalB
    elif 'smbXsrv_client' in args.path:
        ndr_type = smbXsrv.client_globalB
        watched = True
    elif 'smbXsrv_tcon' in args.path:
        ndr_type = smbXsrv.tcon_globalB
    elif 'smbXsrv_version' in args.path:
        ndr_type = smbXsrv.version_globalB
    else:
        raise Exception("Failed to guess NDR type")

    tdb = tdb.Tdb(args.path, 0, tdb.INCOMPATIBLE_HASH, os.O_RDONLY)

    i = 1
    for k in tdb.keys():
        data = tdb.get(k)
        print("Record: %d" % i)
        print_record(data, ndr_type, watched, args.ctdb)
        i = i + 1

    tdb.close()
