1#!/usr/bin/python3
2#
3# Unix SMB/CIFS implementation.
4# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2019
5#
6# Downgrade a database from 4.11 format to 4.7 format. 4.7 Format will
7# run on any version of Samba AD, and Samba will repack/reconfigure the
8# database if necessary.
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 3 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22from __future__ import print_function
23import optparse
24import sys
25
26# Find right directory when running from source tree
27sys.path.insert(0, "bin/python")
28
29
30import samba
31import ldb
32import urllib
33import os
34from samba import getopt as options
35from samba.samdb import SamDB
36from samba.dbchecker import dbcheck
37from samba.credentials import Credentials
38parser = optparse.OptionParser("sambaundoguididx")
39sambaopts = options.SambaOptions(parser)
40parser.add_option_group(options.VersionOptions(parser))
41parser.add_option("-H", "--URL", help="LDB URL for database",
42                  type=str, metavar="URL", dest="H")
43opts, args = parser.parse_args()
44
45if len(args) != 0:
46    parser.print_usage()
47    sys.exit(1)
48
49lp_ctx = sambaopts.get_loadparm()
50
51if opts.H is None:
52    url = lp_ctx.private_path("sam.ldb")
53else:
54    url = opts.H
55
56samdb = ldb.Ldb(url=url,
57                flags=ldb.FLG_DONT_CREATE_DB,
58                options=["modules:"])
59
60partitions = samdb.search(base="@PARTITION",
61                          scope=ldb.SCOPE_BASE,
62                          attrs=["backendStore", "partition"])
63
64backend = str(partitions[0].get('backendStore', 'tdb'))
65
66if backend == "mdb":
67    samdb = None
68    options = ["pack_format_override=%d" % ldb.PACKING_FORMAT]
69    # We can't remove GUID indexes from LMDB in case there are very
70    # long DNs, so we just move down the pack format, which also removes
71    # references to ORDERED_INTEGER in @ATTRIBUTES.
72
73    # Reopen the DB with pack_format_override set
74    samdb = SamDB(url=url,
75                  flags=ldb.FLG_DONT_CREATE_DB,
76                  lp=lp_ctx,
77                  options=options)
78    samdb.transaction_start()
79    samdb.transaction_commit()
80    print("Your database has been downgraded to LDB pack format version %0x (v1)." % ldb.PACKING_FORMAT)
81
82    print("NOTE: Any use of a Samba 4.11 tool that modifies the DB will "
83          "auto-upgrade back to pack format version %0x (v2)" %
84          ldb.PACKING_FORMAT_V2)
85    exit(0);
86
87# This is needed to force the @ATTRIBUTES and @INDEXLIST to be correct
88lp_ctx.set("dsdb:guid index", "false")
89
90modmsg = ldb.Message()
91modmsg.dn = ldb.Dn(samdb, '@INDEXLIST')
92modmsg.add(ldb.MessageElement(
93    elements=[],
94    flags=ldb.FLAG_MOD_REPLACE,
95    name='@IDXGUID'))
96modmsg.add(ldb.MessageElement(
97    elements=[],
98    flags=ldb.FLAG_MOD_REPLACE,
99    name='@IDX_DN_GUID'))
100
101samdb.transaction_start()
102samdb.modify(modmsg)
103
104privatedir = os.path.dirname(url)
105
106dbs = []
107for part in partitions[0]['partition']:
108    dbname = str(part).split(":")[1]
109    dbpath = os.path.join(privatedir, dbname)
110    if os.path.isfile(dbpath):
111        dbpath = "ldb://" + dbpath
112    db = ldb.Ldb(url=dbpath,
113                 options=["modules:"],
114                 flags=ldb.FLG_DONT_CREATE_DB)
115    db.transaction_start()
116    db.modify(modmsg)
117    dbs.append(db)
118
119for db in dbs:
120    db.transaction_commit()
121
122samdb.transaction_commit()
123
124print("Re-opening with the full DB stack")
125samdb = SamDB(url=url,
126              flags=ldb.FLG_DONT_CREATE_DB,
127              lp=lp_ctx)
128print("Re-triggering another re-index")
129chk = dbcheck(samdb)
130
131chk.reindex_database()
132
133print("Your database has been downgraded to DN-based index values.")
134
135print("NOTE: Any use of a Samba 4.8 or later tool including ldbsearch will "
136      "auto-upgrade back to GUID index mode")
137