3 # implement samba_tool gpo commands
5 # Copyright Andrew Tridgell 2010
6 # Copyright Giampaolo Lauria 2011 <lauria2@yahoo.com>
7 # Copyright Amitay Isaacs 2011 <amitay@gmail.com>
9 # based on C implementation by Guenther Deschner and Wilco Baan Hofman
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import samba
.getopt
as options
29 from samba
.auth
import system_session
30 from samba
.netcmd
import (
36 from samba
.samdb
import SamDB
37 from samba
import dsdb
, dcerpc
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
48 def samdb_connect(ctx
):
49 '''make a ldap connection to the server'''
51 ctx
.samdb
= SamDB(url
=ctx
.url
,
52 session_info
=system_session(),
53 credentials
=ctx
.creds
, lp
=ctx
.lp
)
55 raise CommandError("LDAP connection to %s failed " % ctx
.url
, e
)
58 def attr_default(msg
, attrname
, default
):
59 '''get an attribute from a ldap msg with a default'''
61 return msg
[attrname
][0]
65 def gpo_flags_string(value
):
66 '''return gpo flags string'''
67 flags
= policy
.get_gpo_flags(value
)
75 def gplink_options_string(value
):
76 '''return gplink options string'''
77 options
= policy
.get_gplink_options(value
)
81 ret
= ' '.join(options
)
85 def parse_gplink(gplink
):
86 '''parse a gPLink into an array of dn and options'''
93 if len(d
) != 2 or not d
[0].startswith("[LDAP://"):
94 raise RuntimeError("Badly formed gPLink '%s'" % g
)
95 ret
.append({ 'dn' : d
[0][8:], 'options' : int(d
[1])})
99 def encode_gplink(gplist
):
100 '''Encode an array of dn and options into gPLink string'''
103 ret
+= "[LDAP://%s;%d]" % (g
['dn'], g
['options'])
107 def dc_url(lp
, creds
, url
=None, dc
=None):
108 '''If URL is not specified, return URL for writable DC.
109 If dc is provided, use that to construct ldap URL'''
114 dc
= netcmd_finddc(lp
, creds
)
116 raise RunTimeError("Could not find a DC for domain", e
)
121 def get_gpo_dn(samdb
, gpo
):
122 '''Construct the DN for gpo'''
124 dn
= samdb
.get_default_basedn()
125 dn
.add_child(ldb
.Dn(samdb
, "CN=Policies,DC=System"))
126 dn
.add_child(ldb
.Dn(samdb
, "CN=%s" % gpo
))
130 def get_gpo_info(samdb
, gpo
=None, displayname
=None, dn
=None):
131 '''Get GPO information using gpo, displayname or dn'''
133 policies_dn
= samdb
.get_default_basedn()
134 policies_dn
.add_child(ldb
.Dn(samdb
, "CN=Policies,CN=System"))
136 base_dn
= policies_dn
137 search_expr
= "(objectClass=groupPolicyContainer)"
138 search_scope
= ldb
.SCOPE_ONELEVEL
141 search_expr
= "(&(objectClass=groupPolicyContainer)(name=%s))" % ldb
.binary_encode(gpo
)
143 if displayname
is not None:
144 search_expr
= "(&(objectClass=groupPolicyContainer)(displayname=%s))" % ldb
.binary_encode(displayname
)
148 search_scope
= ldb
.SCOPE_BASE
151 msg
= samdb
.search(base
=base_dn
, scope
=search_scope
,
152 expression
=search_expr
,
153 attrs
=['nTSecurityDescriptor',
161 mesg
= "Cannot get information for GPO %s" % gpo
163 mesg
= "Cannot get information for GPOs"
164 raise CommandError(mesg
, e
)
170 '''Parse UNC string into a hostname, a service, and a filepath'''
171 if unc
.startswith('\\\\') and unc
.startswith('//'):
172 raise ValueError("UNC doesn't start with \\\\ or //")
173 tmp
= unc
[2:].split('/', 2)
176 tmp
= unc
[2:].split('\\', 2)
179 raise ValueError("Invalid UNC string: %s" % unc
)
182 def copy_directory_remote_to_local(conn
, remotedir
, localdir
):
183 if not os
.path
.isdir(localdir
):
185 r_dirs
= [ remotedir
]
186 l_dirs
= [ localdir
]
191 dirlist
= conn
.list(r_dir
)
193 r_name
= r_dir
+ '\\' + e
['name']
194 l_name
= os
.path
.join(l_dir
, e
['name'])
196 if e
['attrib'] & smb
.FILE_ATTRIBUTE_DIRECTORY
:
197 r_dirs
.append(r_name
)
198 l_dirs
.append(l_name
)
201 data
= conn
.loadfile(r_name
)
202 file(l_name
, 'w').write(data
)
205 def copy_directory_local_to_remote(conn
, localdir
, remotedir
):
206 if not conn
.chkpath(remotedir
):
207 conn
.mkdir(remotedir
)
208 l_dirs
= [ localdir
]
209 r_dirs
= [ remotedir
]
214 dirlist
= os
.listdir(l_dir
)
216 l_name
= os
.path
.join(l_dir
, e
)
217 r_name
= r_dir
+ '\\' + e
219 if os
.path
.isdir(l_name
):
220 l_dirs
.append(l_name
)
221 r_dirs
.append(r_name
)
224 data
= file(l_name
, 'r').read()
225 conn
.savefile(r_name
, data
)
228 def create_directory_hier(conn
, remotedir
):
229 elems
= remotedir
.replace('/', '\\').split('\\')
232 path
= path
+ '\\' + e
233 if not conn
.chkpath(path
):
237 class cmd_listall(Command
):
240 synopsis
= "%prog gpo listall [options]"
243 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
244 metavar
="URL", dest
="H")
247 def run(self
, H
=None, sambaopts
=None, credopts
=None, versionopts
=None):
249 self
.lp
= sambaopts
.get_loadparm()
250 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
252 self
.url
= dc_url(self
.lp
, self
.creds
, H
)
256 msg
= get_gpo_info(self
.samdb
, None)
259 print("GPO : %s" % m
['name'][0])
260 print("display name : %s" % m
['displayName'][0])
261 print("path : %s" % m
['gPCFileSysPath'][0])
262 print("dn : %s" % m
.dn
)
263 print("version : %s" % attr_default(m
, 'versionNumber', '0'))
264 print("flags : %s" % gpo_flags_string(int(attr_default(m
, 'flags', 0))))
268 class cmd_list(Command
):
269 """list GPOs for an account"""
271 synopsis
= "%prog gpo list <username> [options]"
273 takes_args
= [ 'username' ]
276 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
277 metavar
="URL", dest
="H")
280 def run(self
, username
, H
=None, sambaopts
=None, credopts
=None, versionopts
=None):
282 self
.lp
= sambaopts
.get_loadparm()
283 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
285 self
.url
= dc_url(self
.lp
, self
.creds
, H
)
290 msg
= self
.samdb
.search(expression
='(&(|(samAccountName=%s)(samAccountName=%s$))(objectClass=User))' %
291 (ldb
.binary_encode(username
),ldb
.binary_encode(username
)))
294 raise CommandError("Failed to find account %s" % username
, e
)
296 # check if its a computer account
298 msg
= self
.samdb
.search(base
=user_dn
, scope
=ldb
.SCOPE_BASE
, attrs
=['objectClass'])[0]
299 is_computer
= 'computer' in msg
['objectClass']
301 raise CommandError("Failed to find objectClass for user %s" % username
, e
)
303 session_info_flags
= ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
304 AUTH_SESSION_INFO_AUTHENTICATED
)
306 # When connecting to a remote server, don't look up the local privilege DB
307 if self
.url
is not None and self
.url
.startswith('ldap'):
308 session_info_flags |
= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
310 session
= samba
.auth
.user_session(self
.samdb
, lp_ctx
=self
.lp
, dn
=user_dn
,
311 session_info_flags
=session_info_flags
)
313 token
= session
.security_token
318 dn
= ldb
.Dn(self
.samdb
, str(user_dn
)).parent()
320 msg
= self
.samdb
.search(base
=dn
, scope
=ldb
.SCOPE_BASE
, attrs
=['gPLink', 'gPOptions'])[0]
322 glist
= parse_gplink(msg
['gPLink'][0])
324 if not inherit
and not (g
['options'] & dsdb
.GPLINK_OPT_ENFORCE
):
326 if g
['options'] & dsdb
.GPLINK_OPT_DISABLE
:
330 gmsg
= self
.samdb
.search(base
=g
['dn'], scope
=ldb
.SCOPE_BASE
,
331 attrs
=['name', 'displayName', 'flags',
332 'ntSecurityDescriptor'])
334 print("Failed to fetch gpo object %s" % g
['dn'])
337 secdesc_ndr
= gmsg
[0]['ntSecurityDescriptor'][0]
338 secdesc
= ndr_unpack(dcerpc
.security
.descriptor
, secdesc_ndr
)
341 samba
.security
.access_check(secdesc
, token
,
342 dcerpc
.security
.SEC_STD_READ_CONTROL |
343 dcerpc
.security
.SEC_ADS_LIST |
344 dcerpc
.security
.SEC_ADS_READ_PROP
)
346 print("Failed access check on %s" % msg
.dn
)
349 # check the flags on the GPO
350 flags
= int(attr_default(gmsg
[0], 'flags', 0))
351 if is_computer
and (flags
& dsdb
.GPO_FLAG_MACHINE_DISABLE
):
353 if not is_computer
and (flags
& dsdb
.GPO_FLAG_USER_DISABLE
):
355 gpos
.append((gmsg
[0]['displayName'][0], gmsg
[0]['name'][0]))
357 # check if this blocks inheritance
358 gpoptions
= int(attr_default(msg
, 'gPOptions', 0))
359 if gpoptions
& dsdb
.GPO_BLOCK_INHERITANCE
:
362 if dn
== self
.samdb
.get_default_basedn():
371 print("GPOs for %s %s" % (msg_str
, username
))
373 print(" %s %s" % (g
[0], g
[1]))
376 class cmd_show(Command
):
377 """Show information for a GPO"""
379 synopsis
= "%prog gpo show <gpo> [options]"
381 takes_optiongroups
= {
382 "sambaopts": options
.SambaOptions
,
383 "versionopts": options
.VersionOptions
,
384 "credopts": options
.CredentialsOptions
,
387 takes_args
= [ 'gpo' ]
390 Option("-H", help="LDB URL for database or target server", type=str)
393 def run(self
, gpo
, H
=None, sambaopts
=None, credopts
=None, versionopts
=None):
395 self
.lp
= sambaopts
.get_loadparm()
396 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
398 self
.url
= dc_url(self
.lp
, self
.creds
, H
)
403 msg
= get_gpo_info(self
.samdb
, gpo
)[0]
405 raise CommandError("GPO %s does not exist" % gpo
, e
)
407 secdesc_ndr
= msg
['ntSecurityDescriptor'][0]
408 secdesc
= ndr_unpack(dcerpc
.security
.descriptor
, secdesc_ndr
)
410 print("GPO : %s" % msg
['name'][0])
411 print("display name : %s" % msg
['displayName'][0])
412 print("path : %s" % msg
['gPCFileSysPath'][0])
413 print("dn : %s" % msg
.dn
)
414 print("version : %s" % attr_default(msg
, 'versionNumber', '0'))
415 print("flags : %s" % gpo_flags_string(int(attr_default(msg
, 'flags', 0))))
416 print("ACL : %s" % secdesc
.as_sddl())
420 class cmd_getlink(Command
):
421 """List GPO Links for a container"""
423 synopsis
= "%prog gpo getlink <container_dn> [options]"
425 takes_optiongroups
= {
426 "sambaopts": options
.SambaOptions
,
427 "versionopts": options
.VersionOptions
,
428 "credopts": options
.CredentialsOptions
,
431 takes_args
= [ 'container_dn' ]
434 Option("-H", help="LDB URL for database or target server", type=str)
437 def run(self
, container_dn
, H
=None, sambaopts
=None, credopts
=None,
440 self
.lp
= sambaopts
.get_loadparm()
441 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
443 self
.url
= dc_url(self
.lp
, self
.creds
, H
)
448 msg
= self
.samdb
.search(base
=container_dn
, scope
=ldb
.SCOPE_BASE
,
449 expression
="(objectClass=*)",
452 raise CommandError("Could not find Container DN %s (%s)" % container_dn
, e
)
455 print("GPO(s) linked to DN %s" % container_dn
)
456 gplist
= parse_gplink(msg
['gPLink'][0])
458 msg
= get_gpo_info(self
.samdb
, dn
=g
['dn'])
459 print(" GPO : %s" % msg
[0]['name'][0])
460 print(" Name : %s" % msg
[0]['displayName'][0])
461 print(" Options : %s" % gplink_options_string(g
['options']))
464 print("No GPO(s) linked to DN=%s" % container_dn
)
467 class cmd_setlink(Command
):
468 """Add or Update a GPO link to a container"""
470 synopsis
= "%prog gpo setlink <container_dn> <gpo> [options]"
472 takes_optiongroups
= {
473 "sambaopts": options
.SambaOptions
,
474 "versionopts": options
.VersionOptions
,
475 "credopts": options
.CredentialsOptions
,
478 takes_args
= [ 'container_dn', 'gpo' ]
481 Option("-H", help="LDB URL for database or target server", type=str),
482 Option("--disable", dest
="disabled", default
=False, action
='store_true',
483 help="Disable policy"),
484 Option("--enforce", dest
="enforced", default
=False, action
='store_true',
485 help="Enforce policy")
488 def run(self
, container_dn
, gpo
, H
=None, disabled
=False, enforced
=False,
489 sambaopts
=None, credopts
=None, versionopts
=None):
491 self
.lp
= sambaopts
.get_loadparm()
492 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
494 self
.url
= dc_url(self
.lp
, self
.creds
, H
)
500 gplink_options |
= dsdb
.GPLINK_OPT_DISABLE
502 gplink_options |
= dsdb
.GPLINK_OPT_ENFORCE
504 # Check if valid GPO DN
506 msg
= get_gpo_info(self
.samdb
, gpo
=gpo
)[0]
508 raise CommandError("GPO %s does not exist" % gpo_dn
, e
)
509 gpo_dn
= get_gpo_dn(self
.samdb
, gpo
)
511 # Check if valid Container DN
513 msg
= self
.samdb
.search(base
=container_dn
, scope
=ldb
.SCOPE_BASE
,
514 expression
="(objectClass=*)",
517 raise CommandError("Could not find container DN %s" % container_dn
, e
)
519 # Update existing GPlinks or Add new one
520 existing_gplink
= False
522 gplist
= parse_gplink(msg
['gPLink'][0])
523 existing_gplink
= True
526 if g
['dn'].lower() == gpo_dn
.lower():
527 g
['options'] = gplink_options
531 gplist
.insert(0, { 'dn' : gpo_dn
, 'options' : gplink_options
})
534 gplist
.append({ 'dn' : gpo_dn
, 'options' : gplink_options
})
536 gplink_str
= encode_gplink(gplist
)
539 m
.dn
= ldb
.Dn(self
.samdb
, container_dn
)
542 m
['new_value'] = ldb
.MessageElement(gplink_str
, ldb
.FLAG_MOD_REPLACE
, 'gPLink')
544 m
['new_value'] = ldb
.MessageElement(gplink_str
, ldb
.FLAG_MOD_ADD
, 'gPLink')
549 raise CommandError("Error adding GPO Link", e
)
551 print("Added/Updated GPO link")
552 cmd_getlink().run(container_dn
, H
, sambaopts
, credopts
, versionopts
)
555 class cmd_dellink(Command
):
556 """Delete GPO link from a container"""
558 synopsis
= "%prog gpo dellink <container_dn> <gpo> [options]"
560 takes_optiongroups
= {
561 "sambaopts": options
.SambaOptions
,
562 "versionopts": options
.VersionOptions
,
563 "credopts": options
.CredentialsOptions
,
566 takes_args
= [ 'container_dn', 'gpo' ]
569 Option("-H", help="LDB URL for database or target server", type=str),
572 def run(self
, container_dn
, gpo_dn
, H
=None, sambaopts
=None, credopts
=None,
575 self
.lp
= sambaopts
.get_loadparm()
576 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
578 self
.url
= dc_url(self
.lp
, self
.creds
, H
)
584 msg
= get_gpo_info(self
.sambdb
, gpo
=gpo
)[0]
586 raise CommandError("GPO %s does not exist" % gpo
, e
)
587 gpo_dn
= get_gpo_dn(self
.samdb
, gpo
)
589 # Check if valid Container DN and get existing GPlinks
591 msg
= self
.samdb
.search(base
=container_dn
, scope
=ldb
.SCOPE_BASE
,
592 expression
="(objectClass=*)",
595 raise CommandError("Could not find container DN %s" % dn
, e
)
598 gplist
= parse_gplink(msg
['gPLink'][0])
600 if g
['dn'].lower() == gpo_dn
.lower():
604 raise CommandError("Specified GPO is not linked to this container")
607 m
.dn
= ldb
.Dn(self
.samdb
, container_dn
)
610 gplink_str
= encode_gplink(gplist
)
611 m
['new_value'] = ldb
.MessageElement(gplink_str
, ldb
.FLAG_MOD_REPLACE
, 'gPLink')
613 m
['new_value'] = ldb
.MessageElement('', ldb
.FLAG_MOD_DELETE
, 'gPLink')
618 raise CommandError("Error Removing GPO Link (%s)" % e
)
620 print("Deleted GPO link.")
621 cmd_getlink().run(container_dn
, H
, sambaopts
, credopts
, versionopts
)
624 class cmd_getinheritance(Command
):
625 """Get inheritance flag for a container"""
627 synopsis
= "%prog gpo getinheritance <container_dn> [options]"
629 takes_optiongroups
= {
630 "sambaopts": options
.SambaOptions
,
631 "versionopts": options
.VersionOptions
,
632 "credopts": options
.CredentialsOptions
,
635 takes_args
= [ 'container_dn' ]
638 Option("-H", help="LDB URL for database or target server", type=str)
641 def run(self
, container_dn
, H
=None, sambaopts
=None, credopts
=None,
645 self
.lp
= sambaopts
.get_loadparm()
647 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
652 msg
= self
.samdb
.search(base
=container_dn
, scope
=ldb
.SCOPE_BASE
,
653 expression
="(objectClass=*)",
654 attrs
=['gPOptions'])[0]
656 raise CommandError("Could not find Container DN %s" % container_dn
, e
)
659 if 'gPOptions' in msg
:
660 inheritance
= int(msg
['gPOptions'][0])
662 if inheritance
== dsdb
.GPO_BLOCK_INHERITANCE
:
663 print("Container has GPO_BLOCK_INHERITANCE")
665 print("Container has GPO_INHERIT")
668 class cmd_setinheritance(Command
):
669 """Set inheritance flag on a container"""
671 synopsis
= "%prog gpo setinheritance <container_dn> <block|inherit> [options]"
673 takes_optiongroups
= {
674 "sambaopts": options
.SambaOptions
,
675 "versionopts": options
.VersionOptions
,
676 "credopts": options
.CredentialsOptions
,
679 takes_args
= [ 'container_dn', 'inherit_state' ]
682 Option("-H", help="LDB URL for database or target server", type=str)
685 def run(self
, container_dn
, inherit_state
, H
=None, sambaopts
=None, credopts
=None,
688 if inherit_state
.lower() == 'block':
689 inheritance
= dsdb
.GPO_BLOCK_INHERITANCE
690 elif inherit_state
.lower() == 'inherit':
691 inheritance
= dsdb
.GPO_INHERIT
693 raise CommandError("Unknown inheritance state (%s)" % inherit_state
)
696 self
.lp
= sambaopts
.get_loadparm()
698 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
703 msg
= self
.samdb
.search(base
=container_dn
, scope
=ldb
.SCOPE_BASE
,
704 expression
="(objectClass=*)",
705 attrs
=['gPOptions'])[0]
707 raise CommandError("Could not find Container DN %s" % container_dn
, e
)
710 m
.dn
= ldb
.Dn(self
.samdb
, container_dn
)
712 if 'gPOptions' in msg
:
713 m
['new_value'] = ldb
.MessageElement(str(inheritance
), ldb
.FLAG_MOD_REPLACE
, 'gPOptions')
715 m
['new_value'] = ldb
.MessageElement(str(inheritance
), ldb
.FLAG_MOD_ADD
, 'gPOptions')
720 raise CommandError("Error setting inheritance state %s" % inherit_state
, e
)
723 class cmd_fetch(Command
):
726 synopsis
= "%prog gpo fetch <gpo> [options]"
728 takes_optiongroups
= {
729 "sambaopts": options
.SambaOptions
,
730 "versionopts": options
.VersionOptions
,
731 "credopts": options
.CredentialsOptions
,
734 takes_args
= [ 'gpo' ]
737 Option("-H", help="LDB URL for database or target server", type=str),
738 Option("--tmpdir", help="Temporary directory for copying policy files", type=str)
741 def run(self
, gpo
, H
=None, tmpdir
=None, sambaopts
=None, credopts
=None, versionopts
=None):
743 self
.lp
= sambaopts
.get_loadparm()
744 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
746 dc_hostname
= netcmd_finddc(self
.lp
, self
.creds
)
747 self
.url
= dc_url(self
.lp
, self
.creds
, H
, dc
=dc_hostname
)
751 msg
= get_gpo_info(self
.samdb
, gpo
)[0]
753 raise CommandError("GPO %s does not exist" % gpo
)
756 unc
= msg
['gPCFileSysPath'][0]
758 [dom_name
, service
, sharepath
] = parse_unc(unc
)
760 raise CommandError("Invalid GPO path (%s)" % unc
)
764 conn
= smb
.SMB(dc_hostname
, service
, lp
=self
.lp
, creds
=self
.creds
)
766 raise CommandError("Error connecting to '%s' using SMB" % dc_hostname
, e
)
771 if not os
.path
.isdir(tmpdir
):
772 raise CommandError("Temoprary directory '%s' does not exist" % tmpdir
)
774 localdir
= os
.path
.join(tmpdir
, "policy")
775 if not os
.path
.isdir(localdir
):
778 gpodir
= os
.path
.join(localdir
, gpo
)
779 if os
.path
.isdir(gpodir
):
780 raise CommandError("GPO directory '%s' already exists, refusing to overwrite" % gpodir
)
784 copy_directory_remote_to_local(conn
, sharepath
, gpodir
)
786 raise CommandError("Error copying GPO from DC", e
)
787 print('GPO copied to %s' % gpodir
)
790 class cmd_create(Command
):
791 """Create an empty GPO"""
793 synopsis
= "%prog gpo create <displayname> [options]"
795 takes_optiongroups
= {
796 "sambaopts": options
.SambaOptions
,
797 "versionopts": options
.VersionOptions
,
798 "credopts": options
.CredentialsOptions
,
801 takes_args
= [ 'displayname' ]
804 Option("-H", help="LDB URL for database or target server", type=str),
805 Option("--tmpdir", help="Temporary directory for copying policy files", type=str)
808 def run(self
, displayname
, H
=None, tmpdir
=None, sambaopts
=None, credopts
=None,
811 self
.lp
= sambaopts
.get_loadparm()
812 self
.creds
= credopts
.get_credentials(self
.lp
, fallback_machine
=True)
814 self
.url
= dc_url(self
.lp
, self
.creds
, H
)
816 dc_hostname
= netcmd_finddc(self
.lp
, self
.creds
)
819 msg
= get_gpo_info(self
.samdb
, displayname
=displayname
)
821 raise CommandError("A GPO already existing with name '%s'" % displayname
)
824 guid
= str(uuid
.uuid4())
825 gpo
= "{%s}" % guid
.upper()
826 realm
= self
.lp
.get('realm')
827 unc_path
= "\\\\%s\\sysvol\\%s\\Policies\\%s" % (realm
, realm
, gpo
)
832 if not os
.path
.isdir(tmpdir
):
833 raise CommandError("Temporary directory '%s' does not exist" % tmpdir
)
835 localdir
= os
.path
.join(tmpdir
, "policy")
836 if not os
.path
.isdir(localdir
):
839 gpodir
= os
.path
.join(localdir
, gpo
)
840 if os
.path
.isdir(gpodir
):
841 raise CommandError("GPO directory '%s' already exists, refusing to overwrite" % gpodir
)
845 os
.mkdir(os
.path
.join(gpodir
, "Machine"))
846 os
.mkdir(os
.path
.join(gpodir
, "User"))
847 gpt_contents
= "[General]\r\nVersion=0\r\n"
848 file(os
.path
.join(gpodir
, "GPT.INI"), "w").write(gpt_contents
)
850 raise CommandError("Error Creating GPO files", e
)
853 gpo_dn
= self
.samdb
.get_default_basedn()
854 gpo_dn
.add_child(ldb
.Dn(self
.samdb
, "CN=Policies,CN=System"))
855 gpo_dn
.add_child(ldb
.Dn(self
.samdb
, "CN=%s" % gpo
))
858 m
.dn
= ldb
.Dn(self
.samdb
, gpo_dn
.get_linearized())
859 m
['a01'] = ldb
.MessageElement("groupPolicyContainer", ldb
.FLAG_MOD_ADD
, "objectClass")
860 m
['a02'] = ldb
.MessageElement(displayname
, ldb
.FLAG_MOD_ADD
, "displayName")
861 m
['a03'] = ldb
.MessageElement(unc_path
, ldb
.FLAG_MOD_ADD
, "gPCFileSysPath")
862 m
['a04'] = ldb
.MessageElement("0", ldb
.FLAG_MOD_ADD
, "flags")
863 m
['a05'] = ldb
.MessageElement("0", ldb
.FLAG_MOD_ADD
, "versionNumber")
864 m
['a06'] = ldb
.MessageElement("TRUE", ldb
.FLAG_MOD_ADD
, "showInAdvancedViewOnly")
865 m
['a07'] = ldb
.MessageElement("2", ldb
.FLAG_MOD_ADD
, "gpcFunctionalityVersion")
869 raise CommandError("Error adding GPO in AD", e
)
871 # Add cn=User,cn=<guid>
873 child_dn
.add_child(ldb
.Dn(self
.samdb
, "CN=User"))
876 m
.dn
= ldb
.Dn(self
.samdb
, child_dn
.get_linearized())
877 m
['a01'] = ldb
.MessageElement("container", ldb
.FLAG_MOD_ADD
, "objectClass")
878 m
['a02'] = ldb
.MessageElement("TRUE", ldb
.FLAG_MOD_ADD
, "showInAdvancedViewOnly")
882 raise CommandError("Error adding GPO in AD", e
)
884 # Add cn=User,cn=<guid>
886 child_dn
.add_child(ldb
.Dn(self
.samdb
, "CN=Machine"))
889 m
.dn
= ldb
.Dn(self
.samdb
, child_dn
.get_linearized())
890 m
['a01'] = ldb
.MessageElement("container", ldb
.FLAG_MOD_ADD
, "objectClass")
891 m
['a02'] = ldb
.MessageElement("TRUE", ldb
.FLAG_MOD_ADD
, "showInAdvancedViewOnly")
895 raise CommandError("Error adding GPO in AD", e
)
897 # Copy GPO files over SMB
898 [dom_name
, service
, sharepath
] = parse_unc(unc_path
)
900 conn
= smb
.SMB(dc_hostname
, service
, lp
=self
.lp
, creds
=self
.creds
)
902 raise CommandError("Error connecting to '%s' using SMB" % dc_hostname
, e
)
905 create_directory_hier(conn
, sharepath
)
906 copy_directory_local_to_remote(conn
, gpodir
, sharepath
)
908 raise CommandError("Error Copying GPO to DC", e
)
910 # Get new security descriptor
911 msg
= get_gpo_info(self
.samdb
, gpo
=gpo
)[0]
912 ds_sd_ndr
= msg
['ntSecurityDescriptor'][0]
913 ds_sd
= ndr_unpack(dcerpc
.security
.descriptor
, ds_sd_ndr
)
915 # Create a file system security descriptor
916 fs_sd
= dcerpc
.security
.descriptor()
917 fs_sd
.owner_sid
= ds_sd
.owner_sid
918 fs_sd
.group_sid
= ds_sd
.group_sid
919 fs_sd
.type = ds_sd
.type
920 fs_sd
.revision
= ds_sd
.revision
923 fs_sd
.sacl
= ds_sd
.sacl
927 for ace
in dacl
.aces
:
928 # Don't add the allow for SID_BUILTIN_PREW2K
929 if (not (ace
.type & dcerpc
.security
.SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT
) and
930 ace
.trustee
== dcerpc
.security
.SID_BUILTIN_PREW2K
):
933 # Copy the ace from the directory server security descriptor
936 # Set specific inheritance flags for within the GPO
937 new_ace
.flags |
= (dcerpc
.security
.SEC_ACE_FLAG_OBJECT_INHERIT |
938 dcerpc
.security
.SEC_ACE_FLAG_CONTAINER_INHERIT
)
939 if ace
.trustee
== dcerpc
.security
.SID_CREATOR_OWNER
:
940 new_ace
.flags |
= dcerpc
.security
.SEC_ACE_FLAG_INHERIT_ONLY
942 # Get a directory access mask from the assigned access mask on the ldap object
943 new_ace
.access_mask
= policy
.ads_to_dir_access_mask(ace
.access_mask
)
945 # Add the ace to DACL
946 fs_sd
.dacl_add(new_ace
)
950 conn
.set_acl(sharepath
, fs_sd
)
952 raise CommandError("Error setting ACL on GPT", e
)
954 print "GPO '%s' created as %s" % (displayname
, gpo
)
957 class cmd_gpo(SuperCommand
):
958 """Group Policy Object (GPO) management"""
961 subcommands
["listall"] = cmd_listall()
962 subcommands
["list"] = cmd_list()
963 subcommands
["show"] = cmd_show()
964 subcommands
["getlink"] = cmd_getlink()
965 subcommands
["setlink"] = cmd_setlink()
966 subcommands
["dellink"] = cmd_dellink()
967 subcommands
["getinheritance"] = cmd_getinheritance()
968 subcommands
["setinheritance"] = cmd_setinheritance()
969 subcommands
["fetch"] = cmd_fetch()
970 subcommands
["create"] = cmd_create()