1 # Samba4 AD database checker
3 # Copyright (C) Andrew Tridgell 2011
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 import samba
.getopt
as options
22 from samba
.auth
import system_session
23 from samba
.samdb
import SamDB
24 from samba
.netcmd
import (
29 from samba
.dbchecker
import dbcheck
30 from samba
import colour
33 class cmd_dbcheck(Command
):
34 """Check local AD database for errors."""
35 synopsis
= "%prog [<DN>] [options]"
37 takes_optiongroups
= {
38 "sambaopts": options
.SambaOptions
,
39 "versionopts": options
.VersionOptions
,
40 "credopts": options
.CredentialsOptionsDouble
,
43 def process_yes(option
, opt
, value
, parser
):
48 if ((arg
[:2] == "--" and len(arg
) > 2) or
49 (arg
[:1] == "-" and len(arg
) > 1 and arg
[1] != "-")):
50 setattr(parser
.values
, "yes", True)
52 setattr(parser
.values
, "yes_rules", arg
.split())
55 setattr(parser
.values
, "yes", True)
60 Option("--scope", dest
="scope", default
="SUB",
61 help="Pass search scope that builds DN list. Options: SUB, ONE, BASE"),
62 Option("--fix", dest
="fix", default
=False, action
='store_true',
63 help='Fix any errors found'),
64 Option("--yes", action
='callback', callback
=process_yes
,
65 help="don't confirm changes individually. Applies all as a single transaction (will not succeed if any errors are found)"),
66 Option("--cross-ncs", dest
="cross_ncs", default
=False, action
='store_true',
67 help="cross naming context boundaries"),
68 Option("-v", "--verbose", dest
="verbose", action
="store_true", default
=False,
69 help="Print more details of checking"),
70 Option("-q", "--quiet", action
="store_true", default
=False,
71 help="don't print details of checking"),
72 Option("--attrs", dest
="attrs", default
=None, help="list of attributes to check (space separated)"),
73 Option("--reindex", dest
="reindex", default
=False, action
="store_true", help="force database re-index"),
74 Option("--force-modules", dest
="force_modules", default
=False, action
="store_true", help="force loading of Samba modules and ignore the @MODULES record (for very old databases)"),
75 Option("--reset-well-known-acls",
76 dest
="reset_well_known_acls",
77 default
=False, action
="store_true",
78 help=("reset ACLs on objects with well known default values"
79 " (for updating from early 4.0.x)")),
80 Option("--quick-membership-checks", dest
="quick_membership_checks",
81 help=("Skips missing/orphaned memberOf backlinks checks, "
82 "but speeds up dbcheck dramatically for domains with "
84 default
=False, action
="store_true"),
85 Option("-H", "--URL", help="LDB URL for database or target server (defaults to local SAM database)",
86 type=str, metavar
="URL", dest
="H"),
87 Option("--selftest-check-expired-tombstones",
88 dest
="selftest_check_expired_tombstones", default
=False, action
="store_true",
89 help=Option
.SUPPRESS_HELP
), # This is only used by tests
92 def run(self
, DN
=None, H
=None, verbose
=False, fix
=False, yes
=False,
93 cross_ncs
=False, quiet
=False,
94 scope
="SUB", credopts
=None, sambaopts
=None, versionopts
=None,
95 attrs
=None, reindex
=False, force_modules
=False,
96 quick_membership_checks
=False,
97 reset_well_known_acls
=False,
98 selftest_check_expired_tombstones
=False,
101 if yes_rules
is None:
104 lp
= sambaopts
.get_loadparm()
106 over_ldap
= H
is not None and H
.startswith('ldap')
109 creds
= credopts
.get_credentials(lp
, fallback_machine
=True)
114 samdb
= SamDB(session_info
=system_session(), url
=H
,
115 credentials
=creds
, lp
=lp
, options
=["modules=samba_dsdb"])
118 samdb
= SamDB(session_info
=system_session(), url
=H
,
119 credentials
=creds
, lp
=lp
)
121 raise CommandError("Failed to connect to DB at %s. If this is a really old sam.ldb (before alpha9), then try again with --force-modules" % H
)
123 if H
is None or not over_ldap
:
126 samdb_schema
= SamDB(session_info
=system_session(), url
=None,
127 credentials
=creds
, lp
=lp
)
129 scope_map
= {"SUB": ldb
.SCOPE_SUBTREE
, "BASE": ldb
.SCOPE_BASE
, "ONE": ldb
.SCOPE_ONELEVEL
}
130 scope
= scope
.upper()
131 if scope
not in scope_map
:
132 raise CommandError("Unknown scope %s" % scope
)
133 search_scope
= scope_map
[scope
]
135 controls
= ['show_deleted:1']
137 controls
.append('paged_results:1:1000')
139 controls
.append("search_options:1:2")
144 attrs
= attrs
.split()
146 # The dbcheck module always prints to stdout, not our self.outf
147 # (yes, maybe FIXME).
148 stdout_colour
= colour
.colour_if_wanted(sys
.stdout
,
149 hint
=self
.requested_colour
)
151 started_transaction
= False
153 samdb
.transaction_start()
154 started_transaction
= True
156 chk
= dbcheck(samdb
, samdb_schema
=samdb_schema
, verbose
=verbose
,
157 fix
=fix
, yes
=yes
, quiet
=quiet
,
158 in_transaction
=started_transaction
,
159 quick_membership_checks
=quick_membership_checks
,
160 reset_well_known_acls
=reset_well_known_acls
,
161 check_expired_tombstones
=selftest_check_expired_tombstones
,
162 colour
=stdout_colour
)
164 for option
in yes_rules
:
165 if hasattr(chk
, option
):
166 setattr(chk
, option
, 'ALL')
168 raise CommandError("Invalid fix rule %s" % option
)
171 self
.outf
.write("Re-indexing...\n")
173 if chk
.reindex_database():
174 self
.outf
.write("completed re-index OK\n")
177 self
.outf
.write("Resetting @MODULES...\n")
179 if chk
.reset_modules():
180 self
.outf
.write("completed @MODULES reset OK\n")
183 error_count
= chk
.check_database(DN
=DN
, scope
=search_scope
,
184 controls
=controls
, attrs
=attrs
)
186 if started_transaction
:
187 samdb
.transaction_cancel()
190 if started_transaction
:
191 samdb
.transaction_commit()