3 # implement samba_tool gpo commands
5 # Copyright Andrew Tridgell 2010
6 # Copyright Amitay Isaacs 2011 <amitay@gmail.com>
8 # based on C implementation by Guenther Deschner and Wilco Baan Hofman
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.
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.
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/>.
25 import samba.getopt as options
28 from samba.auth import system_session
29 from samba.netcmd import (
35 from samba.samdb import SamDB
36 from samba import dsdb
37 from samba.dcerpc import security
38 from samba.ndr import ndr_unpack
41 from samba.auth import AUTH_SESSION_INFO_DEFAULT_GROUPS, AUTH_SESSION_INFO_AUTHENTICATED, AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
42 from samba.netcmd.common import netcmd_finddc
43 from samba import policy
46 from samba.ntacls import dsacl2fsacl
49 def samdb_connect(ctx):
50 '''make a ldap connection to the server'''
52 ctx.samdb = SamDB(url=ctx.url,
53 session_info=system_session(),
54 credentials=ctx.creds, lp=ctx.lp)
56 raise CommandError("LDAP connection to %s failed " % ctx.url, e)
59 def attr_default(msg, attrname, default):
60 '''get an attribute from a ldap msg with a default'''
62 return msg[attrname][0]
66 def gpo_flags_string(value):
67 '''return gpo flags string'''
68 flags = policy.get_gpo_flags(value)
76 def gplink_options_string(value):
77 '''return gplink options string'''
78 options = policy.get_gplink_options(value)
82 ret = ' '.join(options)
86 def parse_gplink(gplink):
87 '''parse a gPLink into an array of dn and options'''
94 if len(d) != 2 or not d[0].startswith("[LDAP://"):
95 raise RuntimeError("Badly formed gPLink '%s'" % g)
96 ret.append({ 'dn' : d[0][8:], 'options' : int(d[1])})
100 def encode_gplink(gplist):
101 '''Encode an array of dn and options into gPLink string'''
104 ret += "[LDAP://%s;%d]" % (g['dn'], g['options'])
108 def dc_url(lp, creds, url=None, dc=None):
109 '''If URL is not specified, return URL for writable DC.
110 If dc is provided, use that to construct ldap URL'''
115 dc = netcmd_finddc(lp, creds)
117 raise RuntimeError("Could not find a DC for domain", e)
122 def get_gpo_dn(samdb, gpo):
123 '''Construct the DN for gpo'''
125 dn = samdb.get_default_basedn()
126 dn.add_child(ldb.Dn(samdb, "CN=Policies,DC=System"))
127 dn.add_child(ldb.Dn(samdb, "CN=%s" % gpo))
131 def get_gpo_info(samdb, gpo=None, displayname=None, dn=None):
132 '''Get GPO information using gpo, displayname or dn'''
134 policies_dn = samdb.get_default_basedn()
135 policies_dn.add_child(ldb.Dn(samdb, "CN=Policies,CN=System"))
137 base_dn = policies_dn
138 search_expr = "(objectClass=groupPolicyContainer)"
139 search_scope = ldb.SCOPE_ONELEVEL
142 search_expr = "(&(objectClass=groupPolicyContainer)(name=%s))" % ldb.binary_encode(gpo)
144 if displayname is not None:
145 search_expr = "(&(objectClass=groupPolicyContainer)(displayname=%s))" % ldb.binary_encode(displayname)
149 search_scope = ldb.SCOPE_BASE
152 msg = samdb.search(base=base_dn, scope=search_scope,
153 expression=search_expr,
154 attrs=['nTSecurityDescriptor',
162 mesg = "Cannot get information for GPO %s" % gpo
164 mesg = "Cannot get information for GPOs"
165 raise CommandError(mesg, e)
171 '''Parse UNC string into a hostname, a service, and a filepath'''
172 if unc.startswith('\\\\') and unc.startswith('//'):
173 raise ValueError("UNC doesn't start with \\\\ or //")
174 tmp = unc[2:].split('/', 2)
177 tmp = unc[2:].split('\\', 2)
180 raise ValueError("Invalid UNC string: %s" % unc)
183 def copy_directory_remote_to_local(conn, remotedir, localdir):
184 if not os.path.isdir(localdir):
186 r_dirs = [ remotedir ]
187 l_dirs = [ localdir ]
192 dirlist = conn.list(r_dir)
194 r_name = r_dir + '\\' + e['name']
195 l_name = os.path.join(l_dir, e['name'])
197 if e['attrib'] & smb.FILE_ATTRIBUTE_DIRECTORY:
198 r_dirs.append(r_name)
199 l_dirs.append(l_name)
202 data = conn.loadfile(r_name)
203 file(l_name, 'w').write(data)
206 def copy_directory_local_to_remote(conn, localdir, remotedir):
207 if not conn.chkpath(remotedir):
208 conn.mkdir(remotedir)
209 l_dirs = [ localdir ]
210 r_dirs = [ remotedir ]
215 dirlist = os.listdir(l_dir)
217 l_name = os.path.join(l_dir, e)
218 r_name = r_dir + '\\' + e
220 if os.path.isdir(l_name):
221 l_dirs.append(l_name)
222 r_dirs.append(r_name)
225 data = file(l_name, 'r').read()
226 conn.savefile(r_name, data)
229 def create_directory_hier(conn, remotedir):
230 elems = remotedir.replace('/', '\\').split('\\')
233 path = path + '\\' + e
234 if not conn.chkpath(path):
238 class cmd_listall(Command):
241 synopsis = "%prog [options]"
243 takes_optiongroups = {
244 "sambaopts": options.SambaOptions,
245 "versionopts": options.VersionOptions,
246 "credopts": options.CredentialsOptions,
250 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
251 metavar="URL", dest="H")
254 def run(self, H=None, sambaopts=None, credopts=None, versionopts=None):
256 self.lp = sambaopts.get_loadparm()
257 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
259 self.url = dc_url(self.lp, self.creds, H)
263 msg = get_gpo_info(self.samdb, None)
266 self.outf.write("GPO : %s\n" % m['name'][0])
267 self.outf.write("display name : %s\n" % m['displayName'][0])
268 self.outf.write("path : %s\n" % m['gPCFileSysPath'][0])
269 self.outf.write("dn : %s\n" % m.dn)
270 self.outf.write("version : %s\n" % attr_default(m, 'versionNumber', '0'))
271 self.outf.write("flags : %s\n" % gpo_flags_string(int(attr_default(m, 'flags', 0))))
272 self.outf.write("\n")
275 class cmd_list(Command):
276 """list GPOs for an account"""
278 synopsis = "%prog <username> [options]"
280 takes_args = ['username']
281 takes_optiongroups = {
282 "sambaopts": options.SambaOptions,
283 "versionopts": options.VersionOptions,
284 "credopts": options.CredentialsOptions,
288 Option("-H", "--URL", help="LDB URL for database or target server",
289 type=str, metavar="URL", dest="H")
292 def run(self, username, H=None, sambaopts=None, credopts=None, versionopts=None):
294 self.lp = sambaopts.get_loadparm()
295 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
297 self.url = dc_url(self.lp, self.creds, H)
302 msg = self.samdb.search(expression='(&(|(samAccountName=%s)(samAccountName=%s$))(objectClass=User))' %
303 (ldb.binary_encode(username),ldb.binary_encode(username)))
306 raise CommandError("Failed to find account %s" % username, e)
308 # check if its a computer account
310 msg = self.samdb.search(base=user_dn, scope=ldb.SCOPE_BASE, attrs=['objectClass'])[0]
311 is_computer = 'computer' in msg['objectClass']
313 raise CommandError("Failed to find objectClass for user %s" % username, e)
315 session_info_flags = ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
316 AUTH_SESSION_INFO_AUTHENTICATED )
318 # When connecting to a remote server, don't look up the local privilege DB
319 if self.url is not None and self.url.startswith('ldap'):
320 session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
322 session = samba.auth.user_session(self.samdb, lp_ctx=self.lp, dn=user_dn,
323 session_info_flags=session_info_flags)
325 token = session.security_token
330 dn = ldb.Dn(self.samdb, str(user_dn)).parent()
332 msg = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=['gPLink', 'gPOptions'])[0]
334 glist = parse_gplink(msg['gPLink'][0])
336 if not inherit and not (g['options'] & dsdb.GPLINK_OPT_ENFORCE):
338 if g['options'] & dsdb.GPLINK_OPT_DISABLE:
342 gmsg = self.samdb.search(base=g['dn'], scope=ldb.SCOPE_BASE,
343 attrs=['name', 'displayName', 'flags',
344 'ntSecurityDescriptor'])
346 self.outf.write("Failed to fetch gpo object %s\n" %
350 secdesc_ndr = gmsg[0]['ntSecurityDescriptor'][0]
351 secdesc = ndr_unpack(security.descriptor, secdesc_ndr)
354 samba.security.access_check(secdesc, token,
355 security.SEC_STD_READ_CONTROL |
356 security.SEC_ADS_LIST |
357 security.SEC_ADS_READ_PROP)
359 self.outf.write("Failed access check on %s\n" % msg.dn)
362 # check the flags on the GPO
363 flags = int(attr_default(gmsg[0], 'flags', 0))
364 if is_computer and (flags & dsdb.GPO_FLAG_MACHINE_DISABLE):
366 if not is_computer and (flags & dsdb.GPO_FLAG_USER_DISABLE):
368 gpos.append((gmsg[0]['displayName'][0], gmsg[0]['name'][0]))
370 # check if this blocks inheritance
371 gpoptions = int(attr_default(msg, 'gPOptions', 0))
372 if gpoptions & dsdb.GPO_BLOCK_INHERITANCE:
375 if dn == self.samdb.get_default_basedn():
384 self.outf.write("GPOs for %s %s\n" % (msg_str, username))
386 self.outf.write(" %s %s\n" % (g[0], g[1]))
389 class cmd_show(Command):
390 """Show information for a GPO"""
392 synopsis = "%prog <gpo> [options]"
394 takes_optiongroups = {
395 "sambaopts": options.SambaOptions,
396 "versionopts": options.VersionOptions,
397 "credopts": options.CredentialsOptions,
403 Option("-H", help="LDB URL for database or target server", type=str)
406 def run(self, gpo, H=None, sambaopts=None, credopts=None, versionopts=None):
408 self.lp = sambaopts.get_loadparm()
409 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
411 self.url = dc_url(self.lp, self.creds, H)
416 msg = get_gpo_info(self.samdb, gpo)[0]
418 raise CommandError("GPO %s does not exist" % gpo, e)
420 secdesc_ndr = msg['ntSecurityDescriptor'][0]
421 secdesc = ndr_unpack(security.descriptor, secdesc_ndr)
423 self.outf.write("GPO : %s\n" % msg['name'][0])
424 self.outf.write("display name : %s\n" % msg['displayName'][0])
425 self.outf.write("path : %s\n" % msg['gPCFileSysPath'][0])
426 self.outf.write("dn : %s\n" % msg.dn)
427 self.outf.write("version : %s\n" % attr_default(msg, 'versionNumber', '0'))
428 self.outf.write("flags : %s\n" % gpo_flags_string(int(attr_default(msg, 'flags', 0))))
429 self.outf.write("ACL : %s\n" % secdesc.as_sddl())
430 self.outf.write("\n")
433 class cmd_getlink(Command):
434 """List GPO Links for a container"""
436 synopsis = "%prog <container_dn> [options]"
438 takes_optiongroups = {
439 "sambaopts": options.SambaOptions,
440 "versionopts": options.VersionOptions,
441 "credopts": options.CredentialsOptions,
444 takes_args = ['container_dn']
447 Option("-H", help="LDB URL for database or target server", type=str)
450 def run(self, container_dn, H=None, sambaopts=None, credopts=None,
453 self.lp = sambaopts.get_loadparm()
454 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
456 self.url = dc_url(self.lp, self.creds, H)
461 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
462 expression="(objectClass=*)",
465 raise CommandError("Could not find Container DN %s (%s)" % container_dn, e)
468 self.outf.write("GPO(s) linked to DN %s\n" % container_dn)
469 gplist = parse_gplink(msg['gPLink'][0])
471 msg = get_gpo_info(self.samdb, dn=g['dn'])
472 self.outf.write(" GPO : %s\n" % msg[0]['name'][0])
473 self.outf.write(" Name : %s\n" % msg[0]['displayName'][0])
474 self.outf.write(" Options : %s\n" % gplink_options_string(g['options']))
475 self.outf.write("\n")
477 self.outf.write("No GPO(s) linked to DN=%s\n" % container_dn)
480 class cmd_setlink(Command):
481 """Add or Update a GPO link to a container"""
483 synopsis = "%prog <container_dn> <gpo> [options]"
485 takes_optiongroups = {
486 "sambaopts": options.SambaOptions,
487 "versionopts": options.VersionOptions,
488 "credopts": options.CredentialsOptions,
491 takes_args = ['container_dn', 'gpo']
494 Option("-H", help="LDB URL for database or target server", type=str),
495 Option("--disable", dest="disabled", default=False, action='store_true',
496 help="Disable policy"),
497 Option("--enforce", dest="enforced", default=False, action='store_true',
498 help="Enforce policy")
501 def run(self, container_dn, gpo, H=None, disabled=False, enforced=False,
502 sambaopts=None, credopts=None, versionopts=None):
504 self.lp = sambaopts.get_loadparm()
505 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
507 self.url = dc_url(self.lp, self.creds, H)
513 gplink_options |= dsdb.GPLINK_OPT_DISABLE
515 gplink_options |= dsdb.GPLINK_OPT_ENFORCE
517 # Check if valid GPO DN
519 msg = get_gpo_info(self.samdb, gpo=gpo)[0]
521 raise CommandError("GPO %s does not exist" % gpo_dn, e)
522 gpo_dn = get_gpo_dn(self.samdb, gpo)
524 # Check if valid Container DN
526 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
527 expression="(objectClass=*)",
530 raise CommandError("Could not find container DN %s" % container_dn, e)
532 # Update existing GPlinks or Add new one
533 existing_gplink = False
535 gplist = parse_gplink(msg['gPLink'][0])
536 existing_gplink = True
539 if g['dn'].lower() == gpo_dn.lower():
540 g['options'] = gplink_options
544 gplist.insert(0, { 'dn' : gpo_dn, 'options' : gplink_options })
547 gplist.append({ 'dn' : gpo_dn, 'options' : gplink_options })
549 gplink_str = encode_gplink(gplist)
552 m.dn = ldb.Dn(self.samdb, container_dn)
555 m['new_value'] = ldb.MessageElement(gplink_str, ldb.FLAG_MOD_REPLACE, 'gPLink')
557 m['new_value'] = ldb.MessageElement(gplink_str, ldb.FLAG_MOD_ADD, 'gPLink')
562 raise CommandError("Error adding GPO Link", e)
564 self.outf.write("Added/Updated GPO link\n")
565 cmd_getlink().run(container_dn, H, sambaopts, credopts, versionopts)
568 class cmd_dellink(Command):
569 """Delete GPO link from a container"""
571 synopsis = "%prog <container_dn> <gpo> [options]"
573 takes_optiongroups = {
574 "sambaopts": options.SambaOptions,
575 "versionopts": options.VersionOptions,
576 "credopts": options.CredentialsOptions,
579 takes_args = ['container_dn', 'gpo']
582 Option("-H", help="LDB URL for database or target server", type=str),
585 def run(self, container_dn, gpo_dn, H=None, sambaopts=None, credopts=None,
588 self.lp = sambaopts.get_loadparm()
589 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
591 self.url = dc_url(self.lp, self.creds, H)
597 msg = get_gpo_info(self.sambdb, gpo=gpo)[0]
599 raise CommandError("GPO %s does not exist" % gpo, e)
600 gpo_dn = get_gpo_dn(self.samdb, gpo)
602 # Check if valid Container DN and get existing GPlinks
604 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
605 expression="(objectClass=*)",
608 raise CommandError("Could not find container DN %s" % dn, e)
611 gplist = parse_gplink(msg['gPLink'][0])
613 if g['dn'].lower() == gpo_dn.lower():
617 raise CommandError("Specified GPO is not linked to this container")
620 m.dn = ldb.Dn(self.samdb, container_dn)
623 gplink_str = encode_gplink(gplist)
624 m['new_value'] = ldb.MessageElement(gplink_str, ldb.FLAG_MOD_REPLACE, 'gPLink')
626 m['new_value'] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, 'gPLink')
631 raise CommandError("Error Removing GPO Link (%s)" % e)
633 self.outf.write("Deleted GPO link.\n")
634 cmd_getlink().run(container_dn, H, sambaopts, credopts, versionopts)
637 class cmd_getinheritance(Command):
638 """Get inheritance flag for a container"""
640 synopsis = "%prog <container_dn> [options]"
642 takes_optiongroups = {
643 "sambaopts": options.SambaOptions,
644 "versionopts": options.VersionOptions,
645 "credopts": options.CredentialsOptions,
648 takes_args = ['container_dn']
651 Option("-H", help="LDB URL for database or target server", type=str)
654 def run(self, container_dn, H=None, sambaopts=None, credopts=None,
658 self.lp = sambaopts.get_loadparm()
660 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
665 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
666 expression="(objectClass=*)",
667 attrs=['gPOptions'])[0]
669 raise CommandError("Could not find Container DN %s" % container_dn, e)
672 if 'gPOptions' in msg:
673 inheritance = int(msg['gPOptions'][0])
675 if inheritance == dsdb.GPO_BLOCK_INHERITANCE:
676 self.outf.write("Container has GPO_BLOCK_INHERITANCE\n")
678 self.outf.write("Container has GPO_INHERIT\n")
681 class cmd_setinheritance(Command):
682 """Set inheritance flag on a container"""
684 synopsis = "%prog <container_dn> <block|inherit> [options]"
686 takes_optiongroups = {
687 "sambaopts": options.SambaOptions,
688 "versionopts": options.VersionOptions,
689 "credopts": options.CredentialsOptions,
692 takes_args = [ 'container_dn', 'inherit_state' ]
695 Option("-H", help="LDB URL for database or target server", type=str)
698 def run(self, container_dn, inherit_state, H=None, sambaopts=None, credopts=None,
701 if inherit_state.lower() == 'block':
702 inheritance = dsdb.GPO_BLOCK_INHERITANCE
703 elif inherit_state.lower() == 'inherit':
704 inheritance = dsdb.GPO_INHERIT
706 raise CommandError("Unknown inheritance state (%s)" % inherit_state)
709 self.lp = sambaopts.get_loadparm()
711 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
716 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
717 expression="(objectClass=*)",
718 attrs=['gPOptions'])[0]
720 raise CommandError("Could not find Container DN %s" % container_dn, e)
723 m.dn = ldb.Dn(self.samdb, container_dn)
725 if 'gPOptions' in msg:
726 m['new_value'] = ldb.MessageElement(str(inheritance), ldb.FLAG_MOD_REPLACE, 'gPOptions')
728 m['new_value'] = ldb.MessageElement(str(inheritance), ldb.FLAG_MOD_ADD, 'gPOptions')
733 raise CommandError("Error setting inheritance state %s" % inherit_state, e)
736 class cmd_fetch(Command):
739 synopsis = "%prog <gpo> [options]"
741 takes_optiongroups = {
742 "sambaopts": options.SambaOptions,
743 "versionopts": options.VersionOptions,
744 "credopts": options.CredentialsOptions,
750 Option("-H", help="LDB URL for database or target server", type=str),
751 Option("--tmpdir", help="Temporary directory for copying policy files", type=str)
754 def run(self, gpo, H=None, tmpdir=None, sambaopts=None, credopts=None, versionopts=None):
756 self.lp = sambaopts.get_loadparm()
757 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
759 dc_hostname = netcmd_finddc(self.lp, self.creds)
760 self.url = dc_url(self.lp, self.creds, H, dc=dc_hostname)
764 msg = get_gpo_info(self.samdb, gpo)[0]
766 raise CommandError("GPO %s does not exist" % gpo)
769 unc = msg['gPCFileSysPath'][0]
771 [dom_name, service, sharepath] = parse_unc(unc)
773 raise CommandError("Invalid GPO path (%s)" % unc)
777 conn = smb.SMB(dc_hostname, service, lp=self.lp, creds=self.creds)
779 raise CommandError("Error connecting to '%s' using SMB" % dc_hostname, e)
784 if not os.path.isdir(tmpdir):
785 raise CommandError("Temoprary directory '%s' does not exist" % tmpdir)
787 localdir = os.path.join(tmpdir, "policy")
788 if not os.path.isdir(localdir):
791 gpodir = os.path.join(localdir, gpo)
792 if os.path.isdir(gpodir):
793 raise CommandError("GPO directory '%s' already exists, refusing to overwrite" % gpodir)
797 copy_directory_remote_to_local(conn, sharepath, gpodir)
799 # FIXME: Catch more specific exception
800 raise CommandError("Error copying GPO from DC", e)
801 self.outf.write('GPO copied to %s\n' % gpodir)
804 class cmd_create(Command):
805 """Create an empty GPO"""
807 synopsis = "%prog <displayname> [options]"
809 takes_optiongroups = {
810 "sambaopts": options.SambaOptions,
811 "versionopts": options.VersionOptions,
812 "credopts": options.CredentialsOptions,
815 takes_args = ['displayname']
818 Option("-H", help="LDB URL for database or target server", type=str),
819 Option("--tmpdir", help="Temporary directory for copying policy files", type=str)
822 def run(self, displayname, H=None, tmpdir=None, sambaopts=None, credopts=None,
825 self.lp = sambaopts.get_loadparm()
826 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
828 self.url = dc_url(self.lp, self.creds, url=H)
830 dc_hostname = netcmd_finddc(self.lp, self.creds)
833 msg = get_gpo_info(self.samdb, displayname=displayname)
835 raise CommandError("A GPO already existing with name '%s'" % displayname)
838 guid = str(uuid.uuid4())
839 gpo = "{%s}" % guid.upper()
840 realm = self.lp.get('realm')
841 unc_path = "\\\\%s\\sysvol\\%s\\Policies\\%s" % (realm, realm, gpo)
846 if not os.path.isdir(tmpdir):
847 raise CommandError("Temporary directory '%s' does not exist" % tmpdir)
849 localdir = os.path.join(tmpdir, "policy")
850 if not os.path.isdir(localdir):
853 gpodir = os.path.join(localdir, gpo)
854 if os.path.isdir(gpodir):
855 raise CommandError("GPO directory '%s' already exists, refusing to overwrite" % gpodir)
859 os.mkdir(os.path.join(gpodir, "Machine"))
860 os.mkdir(os.path.join(gpodir, "User"))
861 gpt_contents = "[General]\r\nVersion=0\r\n"
862 file(os.path.join(gpodir, "GPT.INI"), "w").write(gpt_contents)
864 raise CommandError("Error Creating GPO files", e)
866 # Connect to DC over SMB
867 [dom_name, service, sharepath] = parse_unc(unc_path)
869 conn = smb.SMB(dc_hostname, service, lp=self.lp, creds=self.creds)
871 raise CommandError("Error connecting to '%s' using SMB" % dc_hostname, e)
873 self.samdb.transaction_start()
876 gpo_dn = self.samdb.get_default_basedn()
877 gpo_dn.add_child(ldb.Dn(self.samdb, "CN=Policies,CN=System"))
878 gpo_dn.add_child(ldb.Dn(self.samdb, "CN=%s" % gpo))
881 m.dn = ldb.Dn(self.samdb, gpo_dn.get_linearized())
882 m['a01'] = ldb.MessageElement("groupPolicyContainer", ldb.FLAG_MOD_ADD, "objectClass")
883 m['a02'] = ldb.MessageElement(displayname, ldb.FLAG_MOD_ADD, "displayName")
884 m['a03'] = ldb.MessageElement(unc_path, ldb.FLAG_MOD_ADD, "gPCFileSysPath")
885 m['a04'] = ldb.MessageElement("0", ldb.FLAG_MOD_ADD, "flags")
886 m['a05'] = ldb.MessageElement("0", ldb.FLAG_MOD_ADD, "versionNumber")
887 m['a06'] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_ADD, "showInAdvancedViewOnly")
888 m['a07'] = ldb.MessageElement("2", ldb.FLAG_MOD_ADD, "gpcFunctionalityVersion")
891 # Add cn=User,cn=<guid>
893 m.dn = ldb.Dn(self.samdb, "CN=User,%s" % str(gpo_dn))
894 m['a01'] = ldb.MessageElement("container", ldb.FLAG_MOD_ADD, "objectClass")
895 m['a02'] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_ADD, "showInAdvancedViewOnly")
898 # Add cn=Machine,cn=<guid>
900 m.dn = ldb.Dn(self.samdb, "CN=Machine,%s" % str(gpo_dn))
901 m['a01'] = ldb.MessageElement("container", ldb.FLAG_MOD_ADD, "objectClass")
902 m['a02'] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_ADD, "showInAdvancedViewOnly")
905 # Copy GPO files over SMB
906 create_directory_hier(conn, sharepath)
907 copy_directory_local_to_remote(conn, gpodir, sharepath)
909 # Get new security descriptor
910 msg = get_gpo_info(self.samdb, gpo=gpo)[0]
911 ds_sd_ndr = msg['ntSecurityDescriptor'][0]
912 ds_sd = ndr_unpack(security.descriptor, ds_sd_ndr).as_sddl()
914 # Create a file system security descriptor
915 fs_sd = security.descriptor(dsacl2fsacl(ds_sd, self.samdb.get_domain_sid()))
918 conn.set_acl(sharepath, fs_sd)
920 self.samdb.transaction_commit()
922 self.samdb.transaction_cancel()
923 raise RuntimeError("Error adding GPO to AD", e)
925 self.outf.write("GPO '%s' created as %s\n" % (displayname, gpo))
928 class cmd_gpo(SuperCommand):
929 """Group Policy Object (GPO) management"""
932 subcommands["listall"] = cmd_listall()
933 subcommands["list"] = cmd_list()
934 subcommands["show"] = cmd_show()
935 subcommands["getlink"] = cmd_getlink()
936 subcommands["setlink"] = cmd_setlink()
937 subcommands["dellink"] = cmd_dellink()
938 subcommands["getinheritance"] = cmd_getinheritance()
939 subcommands["setinheritance"] = cmd_setinheritance()
940 subcommands["fetch"] = cmd_fetch()
941 subcommands["create"] = cmd_create()