s4:kdc: adjust formatting of samba_kdc_update_pac() documentation
[Samba.git] / python / samba / netcmd / schema.py
blobe665e834a0493e05e5e9a788523ac29232cb73b2
1 # Manipulate ACLs on directory objects
3 # Copyright (C) William Brown <william@blackhats.net.au> 2018
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/>.
19 import ldb
20 import samba.getopt as options
21 from samba.ms_schema import bitFields
22 from samba.auth import system_session
23 from samba.samdb import SamDB
24 from samba.netcmd import (
25 Command,
26 CommandError,
27 SuperCommand,
28 Option
32 class cmd_schema_attribute_modify(Command):
33 """Modify attribute settings in the schema partition.
35 This commands allows minor modifications to attributes in the schema. Active
36 Directory does not allow many changes to schema, but important modifications
37 are related to indexing. This command overwrites the value of searchflags,
38 so be sure to view the current content before making changes.
40 Example1:
41 samba-tool schema attribute modify uid \\
42 --searchflags="fATTINDEX,fPRESERVEONDELETE"
44 This alters the uid attribute to be indexed and to be preserved when
45 converted to a tombstone.
47 Important search flag values are:
49 fATTINDEX: create an equality index for this attribute.
50 fPDNTATTINDEX: create a container index for this attribute (ie OU).
51 fANR: specify that this attribute is a member of the ambiguous name
52 resolution set.
53 fPRESERVEONDELETE: indicate that the value of this attribute should be
54 preserved when the object is converted to a tombstone (deleted).
55 fCOPY: hint to clients that this attribute should be copied.
56 fTUPLEINDEX: create a tuple index for this attribute. This is used in
57 substring queries.
58 fSUBTREEATTINDEX: create a browsing index for this attribute. VLV searches
59 require this.
60 fCONFIDENTIAL: indicate that the attribute is confidential and requires
61 special access checks.
62 fNEVERVALUEAUDIT: indicate that changes to this value should NOT be audited.
63 fRODCFILTEREDATTRIBUTE: indicate that this value should not be replicated to
64 RODCs.
65 fEXTENDEDLINKTRACKING: indicate to the DC to perform extra link tracking.
66 fBASEONLY: indicate that this attribute should only be displayed when the
67 search scope of the query is SCOPE_BASE or a single object result.
68 fPARTITIONSECRET: indicate that this attribute is a partition secret and
69 requires special access checks.
71 The authoritative source of this information is the MS-ADTS.
72 """
73 synopsis = "%prog attribute [options]"
75 takes_optiongroups = {
76 "sambaopts": options.SambaOptions,
77 "versionopts": options.VersionOptions,
78 "credopts": options.CredentialsOptions,
81 takes_options = [
82 Option("--searchflags", help="Search Flags for the attribute", type=str),
83 Option("-H", "--URL", help="LDB URL for database or target server",
84 type=str, metavar="URL", dest="H"),
87 takes_args = ["attribute"]
89 def run(self, attribute, H=None, credopts=None, sambaopts=None,
90 versionopts=None, searchflags=None):
92 if searchflags is None:
93 raise CommandError('A value to modify must be provided.')
95 # Parse the search flags to a set of bits to modify.
97 searchflags_int = None
98 if searchflags is not None:
99 searchflags_int = 0
100 flags = searchflags.split(',')
101 # We have to normalise all the values. To achieve this predictably
102 # we title case (Fattrindex), then swapcase (fATTINDEX)
103 flags = [x.capitalize().swapcase() for x in flags]
104 for flag in flags:
105 if flag not in bitFields['searchflags'].keys():
106 raise CommandError("Unknown flag '%s', please see --help" % flag)
107 bit_loc = 31 - bitFields['searchflags'][flag]
108 # Now apply the bit.
109 searchflags_int = searchflags_int | (1 << bit_loc)
111 lp = sambaopts.get_loadparm()
112 creds = credopts.get_credentials(lp)
114 samdb = SamDB(url=H, session_info=system_session(),
115 credentials=creds, lp=lp)
117 schema_dn = samdb.schema_dn()
118 # For now we make assumptions about the CN
119 attr_dn = 'cn=%s,%s' % (attribute, schema_dn)
121 m = ldb.Message()
122 m.dn = ldb.Dn(samdb, attr_dn)
124 if searchflags_int is not None:
125 m['searchFlags'] = ldb.MessageElement(
126 str(searchflags_int), ldb.FLAG_MOD_REPLACE, 'searchFlags')
128 samdb.modify(m)
129 samdb.set_schema_update_now()
130 self.outf.write("modified %s" % attr_dn)
133 class cmd_schema_attribute_show(Command):
134 """Show details about an attribute from the schema.
136 Schema attribute definitions define and control the behaviour of directory
137 attributes on objects. This displays the details of a single attribute.
139 synopsis = "%prog attribute [options]"
141 takes_optiongroups = {
142 "sambaopts": options.SambaOptions,
143 "versionopts": options.VersionOptions,
144 "credopts": options.CredentialsOptions,
147 takes_options = [
148 Option("-H", "--URL", help="LDB URL for database or target server",
149 type=str, metavar="URL", dest="H"),
152 takes_args = ["attribute"]
154 def run(self, attribute, H=None, credopts=None, sambaopts=None, versionopts=None):
155 lp = sambaopts.get_loadparm()
156 creds = credopts.get_credentials(lp)
158 samdb = SamDB(url=H, session_info=system_session(),
159 credentials=creds, lp=lp)
161 schema_dn = samdb.schema_dn()
163 filt = '(&(objectClass=attributeSchema)(|(lDAPDisplayName={0})(cn={0})(name={0})))'.format(attribute)
165 res = samdb.search(base=schema_dn, scope=ldb.SCOPE_SUBTREE,
166 expression=filt)
168 if len(res) == 0:
169 raise CommandError('No schema objects matched "%s"' % attribute)
170 if len(res) > 1:
171 raise CommandError('Multiple schema objects matched "%s": this is a serious issue you should report!' % attribute)
173 # Get the content of searchFlags (if any) and manipulate them to
174 # show our friendly names.
176 # WARNING: If you are reading this in the future trying to change an
177 # ldb message dynamically, and wondering why you get an operations
178 # error, it's related to talloc references.
180 # When you create *any* python reference, IE:
181 # flags = res[0]['attr']
182 # this creates a talloc_reference that may live forever due to pythons
183 # memory management model. However, when you create this reference it
184 # blocks talloc_realloc from functions in msg.add(element).
186 # As a result, you MUST avoid ALL new variable references UNTIL you have
187 # modified the message as required, even if it makes your code more
188 # verbose.
190 if 'searchFlags' in res[0].keys():
191 flags_i = None
192 try:
193 # See above
194 flags_i = int(str(res[0]['searchFlags']))
195 except ValueError:
196 raise CommandError('Invalid schemaFlags value "%s": this is a serious issue you should report!' % res[0]['searchFlags'])
197 # Work out what keys we have.
198 out = []
199 for flag in bitFields['searchflags'].keys():
200 if flags_i & (1 << (31 - bitFields['searchflags'][flag])) != 0:
201 out.append(flag)
202 if len(out) > 0:
203 res[0].add(ldb.MessageElement(out, ldb.FLAG_MOD_ADD, 'searchFlagsDecoded'))
205 user_ldif = samdb.write_ldif(res[0], ldb.CHANGETYPE_NONE)
206 self.outf.write(user_ldif)
209 class cmd_schema_attribute_show_oc(Command):
210 """Show what objectclasses MAY or MUST contain an attribute.
212 This is useful to determine "if I need uid, what objectclasses could be
213 applied to achieve this."
215 synopsis = "%prog attribute [options]"
217 takes_optiongroups = {
218 "sambaopts": options.SambaOptions,
219 "versionopts": options.VersionOptions,
220 "credopts": options.CredentialsOptions,
223 takes_options = [
224 Option("-H", "--URL", help="LDB URL for database or target server",
225 type=str, metavar="URL", dest="H"),
228 takes_args = ["attribute"]
230 def run(self, attribute, H=None, credopts=None, sambaopts=None, versionopts=None):
231 lp = sambaopts.get_loadparm()
232 creds = credopts.get_credentials(lp)
234 samdb = SamDB(url=H, session_info=system_session(),
235 credentials=creds, lp=lp)
237 schema_dn = samdb.schema_dn()
239 may_filt = '(&(objectClass=classSchema)' \
240 '(|(mayContain={0})(systemMayContain={0})))'.format(attribute)
241 must_filt = '(&(objectClass=classSchema)' \
242 '(|(mustContain={0})(systemMustContain={0})))'.format(attribute)
244 may_res = samdb.search(base=schema_dn, scope=ldb.SCOPE_SUBTREE,
245 expression=may_filt, attrs=['cn'])
246 must_res = samdb.search(base=schema_dn, scope=ldb.SCOPE_SUBTREE,
247 expression=must_filt, attrs=['cn'])
249 self.outf.write('--- MAY contain ---\n')
250 for msg in may_res:
251 self.outf.write('%s\n' % msg['cn'][0])
253 self.outf.write('--- MUST contain ---\n')
254 for msg in must_res:
255 self.outf.write('%s\n' % msg['cn'][0])
258 class cmd_schema_objectclass_show(Command):
259 """Show details about an objectClass from the schema.
261 Schema objectClass definitions define and control the behaviour of directory
262 objects including what attributes they may contain. This displays the
263 details of an objectClass.
265 synopsis = "%prog objectclass [options]"
267 takes_optiongroups = {
268 "sambaopts": options.SambaOptions,
269 "versionopts": options.VersionOptions,
270 "credopts": options.CredentialsOptions,
273 takes_options = [
274 Option("-H", "--URL", help="LDB URL for database or target server",
275 type=str, metavar="URL", dest="H"),
278 takes_args = ["objectclass"]
280 def run(self, objectclass, H=None, credopts=None, sambaopts=None, versionopts=None):
281 lp = sambaopts.get_loadparm()
282 creds = credopts.get_credentials(lp)
284 samdb = SamDB(url=H, session_info=system_session(),
285 credentials=creds, lp=lp)
287 schema_dn = samdb.schema_dn()
289 filt = '(&(objectClass=classSchema)' \
290 '(|(lDAPDisplayName={0})(cn={0})(name={0})))'.format(objectclass)
292 res = samdb.search(base=schema_dn, scope=ldb.SCOPE_SUBTREE,
293 expression=filt)
295 for msg in res:
296 user_ldif = samdb.write_ldif(msg, ldb.CHANGETYPE_NONE)
297 self.outf.write(user_ldif)
300 class cmd_schema_attribute(SuperCommand):
301 """Query and manage attributes in the schema partition."""
302 subcommands = {}
303 subcommands["modify"] = cmd_schema_attribute_modify()
304 subcommands["show"] = cmd_schema_attribute_show()
305 subcommands["show_oc"] = cmd_schema_attribute_show_oc()
308 class cmd_schema_objectclass(SuperCommand):
309 """Query and manage objectclasses in the schema partition."""
310 subcommands = {}
311 subcommands["show"] = cmd_schema_objectclass_show()
314 class cmd_schema(SuperCommand):
315 """Schema querying and management."""
317 subcommands = {}
318 subcommands["attribute"] = cmd_schema_attribute()
319 subcommands["objectclass"] = cmd_schema_objectclass()