2 # -*- coding: utf-8 -*-
4 # script to verify cached prefixMap on remote
5 # server against the prefixMap stored in Schema NC
7 # Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from optparse
import OptionParser
27 sys
.path
.insert(0, "bin/python")
30 import samba
.getopt
as options
31 from ldb
import SCOPE_BASE
, SCOPE_SUBTREE
32 from samba
.dcerpc
import drsuapi
, misc
, drsblobs
33 from samba
.drs_utils
import drs_DsBind
34 from samba
.samdb
import SamDB
35 from samba
.auth
import system_session
36 from samba
.ndr
import ndr_pack
, ndr_unpack
39 def _samdb_fetch_pfm(samdb
):
40 """Fetch prefixMap stored in SamDB using LDB connection"""
41 res
= samdb
.search(base
=samdb
.get_schema_basedn(), expression
="", scope
=SCOPE_BASE
, attrs
=["*"])
43 pfm
= ndr_unpack(drsblobs
.prefixMapBlob
,
44 str(res
[0]['prefixMap']))
46 pfm_schi
= _samdb_fetch_schi(samdb
)
48 return (pfm
.ctr
, pfm_schi
)
51 def _samdb_fetch_schi(samdb
):
52 """Fetch schemaInfo stored in SamDB using LDB connection"""
53 res
= samdb
.search(base
=samdb
.get_schema_basedn(), expression
="", scope
=SCOPE_BASE
, attrs
=["*"])
55 if 'schemaInfo' in res
[0]:
56 pfm_schi
= ndr_unpack(drsblobs
.schemaInfoBlob
,
57 str(res
[0]['schemaInfo']))
59 pfm_schi
= drsblobs
.schemaInfoBlob()
60 pfm_schi
.marker
= 0xFF
64 def _drs_fetch_pfm(server
, samdb
, creds
, lp
):
65 """Fetch prefixMap using DRS interface"""
66 binding_str
= "ncacn_ip_tcp:%s[print,seal]" % server
68 drs
= drsuapi
.drsuapi(binding_str
, lp
, creds
)
69 (drs_handle
, supported_extensions
) = drs_DsBind(drs
)
70 print("DRS Handle: %s" % drs_handle
)
72 req8
= drsuapi
.DsGetNCChangesRequest8()
74 dest_dsa
= misc
.GUID("9c637462-5b8c-4467-aef2-bdb1f57bc4ef")
77 req8
.destination_dsa_guid
= dest_dsa
78 req8
.source_dsa_invocation_id
= misc
.GUID(samdb
.get_invocation_id())
79 req8
.naming_context
= drsuapi
.DsReplicaObjectIdentifier()
80 req8
.naming_context
.dn
= samdb
.get_schema_basedn()
81 req8
.highwatermark
= drsuapi
.DsReplicaHighWaterMark()
82 req8
.highwatermark
.tmp_highest_usn
= 0
83 req8
.highwatermark
.reserved_usn
= 0
84 req8
.highwatermark
.highest_usn
= 0
85 req8
.uptodateness_vector
= None
86 req8
.replica_flags
= replica_flags
87 req8
.max_object_count
= 0
88 req8
.max_ndr_size
= 402116
91 req8
.partial_attribute_set
= None
92 req8
.partial_attribute_set_ex
= None
93 req8
.mapping_ctr
.num_mappings
= 0
94 req8
.mapping_ctr
.mappings
= None
96 (level
, ctr
) = drs
.DsGetNCChanges(drs_handle
, 8, req8
)
98 # check for schemaInfo element
99 pfm_it
= pfm
.mappings
[-1]
100 assert pfm_it
.id_prefix
== 0
101 assert pfm_it
.oid
.length
== 21
102 s
= "".join(chr(x
) for x
in pfm_it
.oid
.binary_oid
)
103 pfm_schi
= ndr_unpack(drsblobs
.schemaInfoBlob
, s
)
104 assert pfm_schi
.marker
== 0xFF
105 # remove schemaInfo element
106 pfm
.num_mappings
-= 1
107 return (pfm
, pfm_schi
)
110 def _pfm_verify(drs_pfm
, ldb_pfm
):
112 if drs_pfm
.num_mappings
!= ldb_pfm
.num_mappings
:
113 errors
.append("Different count of prefixes: drs = %d, ldb = %d"
114 % (drs_pfm
.num_mappings
, ldb_pfm
.num_mappings
))
115 count
= min(drs_pfm
.num_mappings
, ldb_pfm
.num_mappings
)
116 for i
in range(0, count
):
118 drs_it
= drs_pfm
.mappings
[i
]
119 ldb_it
= ldb_pfm
.mappings
[i
]
120 if drs_it
.id_prefix
!= ldb_it
.id_prefix
:
121 it_err
.append("id_prefix")
122 if drs_it
.oid
.length
!= ldb_it
.oid
.length
:
123 it_err
.append("oid.length")
124 if drs_it
.oid
.binary_oid
!= ldb_it
.oid
.binary_oid
:
125 it_err
.append("oid.binary_oid")
127 errors
.append("[%2d] differences in (%s)" % (i
, it_err
))
131 def _pfm_schi_verify(drs_schi
, ldb_schi
):
133 print(drs_schi
.revision
)
134 print(drs_schi
.invocation_id
)
135 if drs_schi
.marker
!= ldb_schi
.marker
:
136 errors
.append("Different marker in schemaInfo: drs = %d, ldb = %d"
137 % (drs_schi
.marker
, ldb_schi
.marker
))
138 if drs_schi
.revision
!= ldb_schi
.revision
:
139 errors
.append("Different revision in schemaInfo: drs = %d, ldb = %d"
140 % (drs_schi
.revision
, ldb_schi
.revision
))
141 if drs_schi
.invocation_id
!= ldb_schi
.invocation_id
:
142 errors
.append("Different invocation_id in schemaInfo: drs = %s, ldb = %s"
143 % (drs_schi
.invocation_id
, ldb_schi
.invocation_id
))
147 ########### main code ###########
148 if __name__
== "__main__":
149 # command line parsing
150 parser
= OptionParser("pfm_verify.py [options] server")
151 sambaopts
= options
.SambaOptions(parser
)
152 parser
.add_option_group(sambaopts
)
153 credopts
= options
.CredentialsOptionsDouble(parser
)
154 parser
.add_option_group(credopts
)
156 (opts
, args
) = parser
.parse_args()
158 lp
= sambaopts
.get_loadparm()
159 creds
= credopts
.get_credentials(lp
)
162 if "DC_SERVER" not in os
.environ
.keys():
163 parser
.error("You must supply a server")
164 args
.append(os
.environ
["DC_SERVER"])
166 if creds
.is_anonymous():
167 parser
.error("You must supply credentials")
171 samdb
= SamDB(url
="ldap://%s" % server
,
172 session_info
=system_session(lp
),
173 credentials
=creds
, lp
=lp
)
176 (drs_pfm
, drs_schi
) = _drs_fetch_pfm(server
, samdb
, creds
, lp
)
177 (ldb_pfm
, ldb_schi
) = _samdb_fetch_pfm(samdb
)
179 errors
= _pfm_verify(drs_pfm
, ldb_pfm
)
181 print("prefixMap verification errors:")
185 errors
= _pfm_schi_verify(drs_schi
, ldb_schi
)
187 print("schemaInfo verification errors:")