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 if 'schemaInfo' in res
[0]:
47 pfm_schi
= pfm_schi
= ndr_unpack(drsblobs
.schemaInfoBlob
,
48 str(res
[0]['schemaInfo']))
50 pfm_schi
= drsblobs
.schemaInfoBlob()
51 pfm_schi
.marker
= 0xFF;
52 return (pfm
.ctr
, pfm_schi
)
54 def _drs_fetch_pfm(server
, samdb
, creds
, lp
):
55 """Fetch prefixMap using DRS interface"""
56 binding_str
= "ncacn_ip_tcp:%s[print,seal]" % server
58 drs
= drsuapi
.drsuapi(binding_str
, lp
, creds
)
59 (drs_handle
, supported_extensions
) = drs_DsBind(drs
)
60 print "DRS Handle: %s" % drs_handle
62 req8
= drsuapi
.DsGetNCChangesRequest8()
64 dest_dsa
= misc
.GUID("9c637462-5b8c-4467-aef2-bdb1f57bc4ef")
67 req8
.destination_dsa_guid
= dest_dsa
68 req8
.source_dsa_invocation_id
= misc
.GUID(samdb
.get_invocation_id())
69 req8
.naming_context
= drsuapi
.DsReplicaObjectIdentifier()
70 req8
.naming_context
.dn
= unicode(samdb
.get_schema_basedn())
71 req8
.highwatermark
= drsuapi
.DsReplicaHighWaterMark()
72 req8
.highwatermark
.tmp_highest_usn
= 0
73 req8
.highwatermark
.reserved_usn
= 0
74 req8
.highwatermark
.highest_usn
= 0
75 req8
.uptodateness_vector
= None
76 req8
.replica_flags
= replica_flags
77 req8
.max_object_count
= 0
78 req8
.max_ndr_size
= 402116
81 req8
.partial_attribute_set
= None
82 req8
.partial_attribute_set_ex
= None
83 req8
.mapping_ctr
.num_mappings
= 0
84 req8
.mapping_ctr
.mappings
= None
86 (level
, ctr
) = drs
.DsGetNCChanges(drs_handle
, 8, req8
)
88 # check for schemaInfo element
89 pfm_it
= pfm
.mappings
[-1]
90 assert pfm_it
.id_prefix
== 0
91 assert pfm_it
.oid
.length
== 21
93 for x
in pfm_it
.oid
.binary_oid
:
95 pfm_schi
= ndr_unpack(drsblobs
.schemaInfoBlob
, s
)
96 assert pfm_schi
.marker
== 0xFF
97 # remove schemaInfo element
99 return (pfm
, pfm_schi
)
101 def _pfm_verify(drs_pfm
, ldb_pfm
):
103 if drs_pfm
.num_mappings
!= ldb_pfm
.num_mappings
:
104 errors
.append("Different count of prefixes: drs = %d, ldb = %d"
105 % (drs_pfm
.num_mappings
, ldb_pfm
.num_mappings
))
106 count
= min(drs_pfm
.num_mappings
, ldb_pfm
.num_mappings
)
107 for i
in range(0, count
):
109 drs_it
= drs_pfm
.mappings
[i
]
110 ldb_it
= ldb_pfm
.mappings
[i
]
111 if drs_it
.id_prefix
!= ldb_it
.id_prefix
:
112 it_err
.append("id_prefix")
113 if drs_it
.oid
.length
!= ldb_it
.oid
.length
:
114 it_err
.append("oid.length")
115 if drs_it
.oid
.binary_oid
!= ldb_it
.oid
.binary_oid
:
116 it_err
.append("oid.binary_oid")
118 errors
.append("[%2d] differences in (%s)" % (i
, it_err
))
121 def _pfm_schi_verify(drs_schi
, ldb_schi
):
123 print drs_schi
.revision
124 print drs_schi
.invocation_id
125 if drs_schi
.marker
!= ldb_schi
.marker
:
126 errors
.append("Different marker in schemaInfo: drs = %d, ldb = %d"
127 % (drs_schi
.marker
, ldb_schi
.marker
))
128 if drs_schi
.revision
!= ldb_schi
.revision
:
129 errors
.append("Different revision in schemaInfo: drs = %d, ldb = %d"
130 % (drs_schi
.revision
, ldb_schi
.revision
))
131 if drs_schi
.invocation_id
!= ldb_schi
.invocation_id
:
132 errors
.append("Different invocation_id in schemaInfo: drs = %s, ldb = %s"
133 % (drs_schi
.invocation_id
, ldb_schi
.invocation_id
))
136 ########### main code ###########
137 if __name__
== "__main__":
138 # command line parsing
139 parser
= OptionParser("pfm_verify.py [options] server")
140 sambaopts
= options
.SambaOptions(parser
)
141 parser
.add_option_group(sambaopts
)
142 credopts
= options
.CredentialsOptionsDouble(parser
)
143 parser
.add_option_group(credopts
)
145 (opts
, args
) = parser
.parse_args()
147 lp
= sambaopts
.get_loadparm()
148 creds
= credopts
.get_credentials(lp
)
152 if not "DC_SERVER" in os
.environ
.keys():
153 parser
.error("You must supply a server")
154 args
.append(os
.environ
["DC_SERVER"])
156 if creds
.is_anonymous():
157 parser
.error("You must supply credentials")
162 samdb
= SamDB(url
="ldap://%s" % server
,
163 session_info
=system_session(lp
),
164 credentials
=creds
, lp
=lp
)
167 (drs_pfm
, drs_schi
) = _drs_fetch_pfm(server
, samdb
, creds
, lp
)
168 (ldb_pfm
, ldb_schi
) = _samdb_fetch_pfm(samdb
)
170 errors
= _pfm_verify(drs_pfm
, ldb_pfm
)
172 print "prefixMap verification errors:"
176 errors
= _pfm_schi_verify(drs_schi
, ldb_schi
)
178 print "schemaInfo verification errors:"