1# domain management
2#
3# Copyright William Brown <william@blackhats.net.au> 2018
4#
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.
9#
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.
14#
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/>.
17#
18
19import ldb
20import samba.getopt as options
21from samba.auth import system_session
22from samba.samdb import SamDB
23from samba.netcmd import (
24    Command,
25    CommandError,
26    SuperCommand,
27    Option
28)
29
30
31class cmd_forest_show(Command):
32    """Display forest settings.
33
34    These settings control the behaviour of all domain controllers in this
35    forest. This displays those settings from the replicated configuration
36    partition.
37    """
38
39    synopsis = "%prog [options]"
40
41    takes_optiongroups = {
42        "sambaopts": options.SambaOptions,
43        "versionopts": options.VersionOptions,
44        "credopts": options.CredentialsOptions,
45    }
46
47    takes_options = [
48        Option("-H", "--URL", help="LDB URL for database or target server",
49               type=str, metavar="URL", dest="H"),
50    ]
51
52    def run(self, H=None, credopts=None, sambaopts=None, versionopts=None):
53        lp = sambaopts.get_loadparm()
54        creds = credopts.get_credentials(lp)
55
56        samdb = SamDB(url=H, session_info=system_session(),
57                      credentials=creds, lp=lp)
58
59        domain_dn = samdb.domain_dn()
60        object_dn = "%s,%s" % (self.objectdn, domain_dn)
61
62        # Show all the settings we know how to set in the forest object!
63        res = samdb.search(base=object_dn, scope=ldb.SCOPE_BASE,
64                           attrs=self.attributes)
65
66        # Now we just display these attributes. The value is that
67        # we make them a bit prettier and human accessible.
68        # There should only be one response!
69        res_object = res[0]
70
71        self.outf.write("Settings for %s\n" % object_dn)
72        for attr in self.attributes:
73            try:
74                self.outf.write("%s: %s\n" % (attr, res_object[attr][0]))
75            except KeyError:
76                self.outf.write("%s: <NO VALUE>\n" % attr)
77
78
79class cmd_forest_set(Command):
80    """Modify forest settings.
81
82    This will alter the setting specified to value.
83    """
84
85    attribute = None
86    objectdn = None
87
88    synopsis = "%prog value [options]"
89
90    takes_optiongroups = {
91        "sambaopts": options.SambaOptions,
92        "versionopts": options.VersionOptions,
93        "credopts": options.CredentialsOptions,
94    }
95
96    takes_options = [
97        Option("-H", "--URL", help="LDB URL for database or target server",
98               type=str, metavar="URL", dest="H"),
99    ]
100
101    takes_args = ["value"]
102
103    def run(self, value, H=None, credopts=None, sambaopts=None, versionopts=None):
104        lp = sambaopts.get_loadparm()
105        creds = credopts.get_credentials(lp)
106
107        samdb = SamDB(url=H, session_info=system_session(),
108                      credentials=creds, lp=lp)
109
110        domain_dn = samdb.domain_dn()
111        object_dn = "%s,%s" % (self.objectdn, domain_dn)
112
113        # Create the modification
114        m = ldb.Message()
115        m.dn = ldb.Dn(samdb, object_dn)
116        m[self.attribute] = ldb.MessageElement(
117            value, ldb.FLAG_MOD_REPLACE, self.attribute)
118
119        samdb.modify(m)
120        self.outf.write("set %s: %s\n" % (self.attribute, value))
121
122
123# Then you override it for each setting name:
124
125class cmd_forest_show_directory_service(cmd_forest_show):
126    """Display Directory Service settings for the forest.
127
128    These settings control how the Directory Service behaves on all domain
129    controllers in the forest.
130    """
131    objectdn = "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration"
132    attributes = ['dsheuristics']
133
134
135class cmd_forest_set_directory_service_dsheuristics(cmd_forest_set):
136    """Set the value of dsheuristics on the Directory Service.
137
138    This value alters the behaviour of the Directory Service on all domain
139    controllers in the forest. Documentation related to this parameter can be
140    found here: https://msdn.microsoft.com/en-us/library/cc223560.aspx
141
142    In summary each "character" of the number-string, controls a setting.
143    A common setting is to set the value "2" in the 7th character. This controls
144    anonymous search behaviour.
145
146    Example: dsheuristics 0000002
147
148    This would allow anonymous LDAP searches to the domain (you may still need
149    to alter access controls to allow this).
150    """
151    objectdn = "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration"
152    attribute = 'dsheuristics'
153
154
155class cmd_forest_directory_service(SuperCommand):
156    """Forest configuration partition management."""
157
158    subcommands = {}
159    subcommands["show"] = cmd_forest_show_directory_service()
160    subcommands["dsheuristics"] = cmd_forest_set_directory_service_dsheuristics()
161
162
163class cmd_forest(SuperCommand):
164    """Forest management."""
165
166    subcommands = {}
167    subcommands["directory_service"] = cmd_forest_directory_service()
168