summaryrefslogtreecommitdiffstats
path: root/source4/scripting/devel/getncchanges
blob: a1a4d14d6212aa119175b01ee3915f5810e5626f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python3

# script to call a DRS GetNCChanges from the command line
# this is useful for plugfest testing
import sys
from optparse import OptionParser

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

import samba, ldb
import samba.getopt as options
from samba.dcerpc import drsuapi, misc
from samba.samdb import SamDB
from samba.auth import system_session
from samba.ndr import ndr_unpack
from samba.drs_utils import drs_get_rodc_partial_attribute_set, drs_DsBind


########### main code ###########
if __name__ == "__main__":
    parser = OptionParser("getncchanges [options] server")
    sambaopts = options.SambaOptions(parser)
    parser.add_option_group(sambaopts)
    credopts = options.CredentialsOptionsDouble(parser)
    parser.add_option_group(credopts)

    parser.add_option("", "--dn", dest="dn", help="DN to replicate",)
    parser.add_option("", "--exop", dest="exop", help="extended operation",)
    parser.add_option("", "--pas", dest="use_pas", action='store_true', default=False,
                      help="send partial attribute set (for RODC)")
    parser.add_option("", "--nb-iter", type='int', help="Number of getncchange iterations")
    parser.add_option("", "--dest-dsa", type='str', help="destination DSA GUID")
    parser.add_option("", "--rodc", action='store_true', default=False,
                      help='use RODC replica flags')
    parser.add_option("", "--partial-rw", action='store_true', default=False,
                      help='use RW partial replica flags, not be confused with --pas')
    parser.add_option("", "--replica-flags", type='int',
                      default=drsuapi.DRSUAPI_DRS_INIT_SYNC |
                      drsuapi.DRSUAPI_DRS_PER_SYNC |
                      drsuapi.DRSUAPI_DRS_WRIT_REP |
                      drsuapi.DRSUAPI_DRS_GET_ANC |
                      drsuapi.DRSUAPI_DRS_NEVER_SYNCED,
                      help='replica flags')

    (opts, args) = parser.parse_args()
    if opts.rodc:
        opts.replica_flags = drsuapi.DRSUAPI_DRS_INIT_SYNC |\
                             drsuapi.DRSUAPI_DRS_PER_SYNC |\
                             drsuapi.DRSUAPI_DRS_GET_ANC |\
                             drsuapi.DRSUAPI_DRS_NEVER_SYNCED |\
                             drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING |\
                             drsuapi.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP

    if opts.partial_rw:
        opts.replica_flags = drsuapi.DRSUAPI_DRS_INIT_SYNC |\
                             drsuapi.DRSUAPI_DRS_PER_SYNC |\
                             drsuapi.DRSUAPI_DRS_GET_ANC |\
                             drsuapi.DRSUAPI_DRS_NEVER_SYNCED

    lp = sambaopts.get_loadparm()
    creds = credopts.get_credentials(lp)

    if len(args) != 1:
        parser.error("You must supply a server")

    if creds.is_anonymous():
        parser.error("You must supply credentials")

    if opts.partial_rw and opts.rodc:
        parser.error("Can't specify --partial-rw and --rodc")

    server = args[0]

    binding_str = "ncacn_ip_tcp:%s[seal,print]" % server

    drs = drsuapi.drsuapi(binding_str, lp, creds)
    drs_handle, supported_extensions = drs_DsBind(drs)
    print("DRS Handle: %s" % drs_handle)

    req8 = drsuapi.DsGetNCChangesRequest8()

    samdb = SamDB(url="ldap://%s" % server,
                  session_info=system_session(),
                  credentials=creds, lp=lp)

    if opts.use_pas:
        local_samdb = SamDB(url=None, session_info=system_session(),
                            credentials=creds, lp=lp)

    if opts.dn is None:
        opts.dn = str(samdb.get_default_basedn())

    if opts.exop is None:
        exop = drsuapi.DRSUAPI_EXOP_NONE
    else:
        exop = int(opts.exop)

    dest_dsa = opts.dest_dsa
    if not dest_dsa:
        print("no dest_dsa specified trying to figure out from ldap")
        msgs = samdb.search(controls=["search_options:1:2"],
                           expression='(objectclass=ntdsdsa)')
        if len(msgs) == 1:
            dest_dsa = str(ndr_unpack(misc.GUID,  msgs[0]["invocationId"][0]))
            print("Found this dsa: %s" % dest_dsa)
        else:
            # TODO fixme
            pass
        if not dest_dsa:
            print("Unable to find the dest_dsa automatically please specify it")
            import sys
            sys.exit(1)

    null_guid = misc.GUID()
    req8.destination_dsa_guid               = misc.GUID(dest_dsa)
    req8.source_dsa_invocation_id	    = misc.GUID(samdb.get_invocation_id())
    req8.naming_context			    = drsuapi.DsReplicaObjectIdentifier()
    req8.naming_context.dn                  = opts.dn.decode("utf-8")
    req8.highwatermark                      = drsuapi.DsReplicaHighWaterMark()
    req8.highwatermark.tmp_highest_usn	    = 0
    req8.highwatermark.reserved_usn	    = 0
    req8.highwatermark.highest_usn	    = 0
    req8.uptodateness_vector		    = None
    req8.replica_flags			    = opts.replica_flags
    req8.max_object_count		     = 402
    req8.max_ndr_size			     = 402116
    req8.extended_op			     = exop
    req8.fsmo_info			     = 0
    if opts.use_pas:
        req8.partial_attribute_set	     = drs_get_rodc_partial_attribute_set(local_samdb)
    else:
        req8.partial_attribute_set	     = None
    req8.partial_attribute_set_ex	     = None
    req8.mapping_ctr.num_mappings	     = 0
    req8.mapping_ctr.mappings		     = None

    nb_iter = 0
    while True:
        (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
        nb_iter += 1
        if ctr.more_data == 0 or opts.nb_iter == nb_iter:
            break
        req8.highwatermark = ctr.new_highwatermark