netcmd: Avoid catching all exceptions, avoid using ';' at the end of lines.
[Samba/gbeck.git] / source4 / scripting / python / samba / netcmd / gpo.py
blob8b96d37d50b609626b64c67e5285efc36de57ccc
1 #!/usr/bin/env python
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/>.
25 import os
26 import samba.getopt as options
27 import ldb
29 from samba.auth import system_session
30 from samba.netcmd import (
31 Command,
32 CommandError,
33 Option,
34 SuperCommand,
36 from samba.samdb import SamDB
37 from samba import dsdb, dcerpc
38 from samba.ndr import ndr_unpack
39 import samba.security
40 import samba.auth
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
44 from samba import smb
45 import uuid
48 def samdb_connect(ctx):
49 '''make a ldap connection to the server'''
50 try:
51 ctx.samdb = SamDB(url=ctx.url,
52 session_info=system_session(),
53 credentials=ctx.creds, lp=ctx.lp)
54 except Exception, e:
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'''
60 if attrname in msg:
61 return msg[attrname][0]
62 return default
65 def gpo_flags_string(value):
66 '''return gpo flags string'''
67 flags = policy.get_gpo_flags(value)
68 if not flags:
69 ret = 'NONE'
70 else:
71 ret = ' '.join(flags)
72 return ret
75 def gplink_options_string(value):
76 '''return gplink options string'''
77 options = policy.get_gplink_options(value)
78 if not options:
79 ret = 'NONE'
80 else:
81 ret = ' '.join(options)
82 return ret
85 def parse_gplink(gplink):
86 '''parse a gPLink into an array of dn and options'''
87 ret = []
88 a = gplink.split(']')
89 for g in a:
90 if not g:
91 continue
92 d = g.split(';')
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])})
96 return ret
99 def encode_gplink(gplist):
100 '''Encode an array of dn and options into gPLink string'''
101 ret = ''
102 for g in gplist:
103 ret += "[LDAP://%s;%d]" % (g['dn'], g['options'])
104 return ret
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'''
111 if url is None:
112 if dc is None:
113 try:
114 dc = netcmd_finddc(lp, creds)
115 except Exception, e:
116 raise RunTimeError("Could not find a DC for domain", e)
117 url = 'ldap://' + dc
118 return url
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))
127 return dn
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
140 if gpo is not None:
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)
146 if dn is not None:
147 base_dn = dn
148 search_scope = ldb.SCOPE_BASE
150 try:
151 msg = samdb.search(base=base_dn, scope=search_scope,
152 expression=search_expr,
153 attrs=['nTSecurityDescriptor',
154 'versionNumber',
155 'flags',
156 'name',
157 'displayName',
158 'gPCFileSysPath'])
159 except Exception, e:
160 if gpo is not None:
161 mesg = "Cannot get information for GPO %s" % gpo
162 else:
163 mesg = "Cannot get information for GPOs"
164 raise CommandError(mesg, e)
166 return msg
169 def parse_unc(unc):
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)
174 if len(tmp) == 3:
175 return tmp
176 tmp = unc[2:].split('\\', 2)
177 if len(tmp) == 3:
178 return tmp
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):
184 os.mkdir(localdir)
185 r_dirs = [ remotedir ]
186 l_dirs = [ localdir ]
187 while r_dirs:
188 r_dir = r_dirs.pop()
189 l_dir = l_dirs.pop()
191 dirlist = conn.list(r_dir)
192 for e in dirlist:
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)
199 os.mkdir(l_name)
200 else:
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 ]
210 while l_dirs:
211 l_dir = l_dirs.pop()
212 r_dir = r_dirs.pop()
214 dirlist = os.listdir(l_dir)
215 for e in dirlist:
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)
222 conn.mkdir(r_name)
223 else:
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('\\')
230 path = ""
231 for e in elems:
232 path = path + '\\' + e
233 if not conn.chkpath(path):
234 conn.mkdir(path)
237 class cmd_listall(Command):
238 """list all GPOs"""
240 synopsis = "%prog gpo listall [options]"
242 takes_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)
254 samdb_connect(self)
256 msg = get_gpo_info(self.samdb, None)
258 for m in msg:
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))))
265 print("")
268 class cmd_list(Command):
269 """list GPOs for an account"""
271 synopsis = "%prog gpo list <username> [options]"
273 takes_args = [ 'username' ]
275 takes_options = [
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)
287 samdb_connect(self)
289 try:
290 msg = self.samdb.search(expression='(&(|(samAccountName=%s)(samAccountName=%s$))(objectClass=User))' %
291 (ldb.binary_encode(username),ldb.binary_encode(username)))
292 user_dn = msg[0].dn
293 except Exception, e:
294 raise CommandError("Failed to find account %s" % username, e)
296 # check if its a computer account
297 try:
298 msg = self.samdb.search(base=user_dn, scope=ldb.SCOPE_BASE, attrs=['objectClass'])[0]
299 is_computer = 'computer' in msg['objectClass']
300 except Exception, e:
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
315 gpos = []
317 inherit = True
318 dn = ldb.Dn(self.samdb, str(user_dn)).parent()
319 while True:
320 msg = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=['gPLink', 'gPOptions'])[0]
321 if 'gPLink' in msg:
322 glist = parse_gplink(msg['gPLink'][0])
323 for g in glist:
324 if not inherit and not (g['options'] & dsdb.GPLINK_OPT_ENFORCE):
325 continue
326 if g['options'] & dsdb.GPLINK_OPT_DISABLE:
327 continue
329 try:
330 gmsg = self.samdb.search(base=g['dn'], scope=ldb.SCOPE_BASE,
331 attrs=['name', 'displayName', 'flags',
332 'ntSecurityDescriptor'])
333 except Exception:
334 print("Failed to fetch gpo object %s" % g['dn'])
335 continue
337 secdesc_ndr = gmsg[0]['ntSecurityDescriptor'][0]
338 secdesc = ndr_unpack(dcerpc.security.descriptor, secdesc_ndr)
340 try:
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)
345 except RuntimeError:
346 print("Failed access check on %s" % msg.dn)
347 continue
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):
352 continue
353 if not is_computer and (flags & dsdb.GPO_FLAG_USER_DISABLE):
354 continue
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:
360 inherit = False
362 if dn == self.samdb.get_default_basedn():
363 break
364 dn = dn.parent()
366 if is_computer:
367 msg_str = 'computer'
368 else:
369 msg_str = 'user'
371 print("GPOs for %s %s" % (msg_str, username))
372 for g in gpos:
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' ]
389 takes_options = [
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)
400 samdb_connect(self)
402 try:
403 msg = get_gpo_info(self.samdb, gpo)[0]
404 except Exception, e:
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())
417 print("")
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' ]
433 takes_options = [
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,
438 versionopts=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)
445 samdb_connect(self)
447 try:
448 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
449 expression="(objectClass=*)",
450 attrs=['gPlink'])[0]
451 except Exception, e:
452 raise CommandError("Could not find Container DN %s (%s)" % container_dn, e)
454 if 'gPLink' in msg:
455 print("GPO(s) linked to DN %s" % container_dn)
456 gplist = parse_gplink(msg['gPLink'][0])
457 for g in gplist:
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']))
462 print("")
463 else:
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' ]
480 takes_options = [
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)
496 samdb_connect(self)
498 gplink_options = 0
499 if disabled:
500 gplink_options |= dsdb.GPLINK_OPT_DISABLE
501 if enforced:
502 gplink_options |= dsdb.GPLINK_OPT_ENFORCE
504 # Check if valid GPO DN
505 try:
506 msg = get_gpo_info(self.samdb, gpo=gpo)[0]
507 except Exception, e:
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
512 try:
513 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
514 expression="(objectClass=*)",
515 attrs=['gPlink'])[0]
516 except Exception, e:
517 raise CommandError("Could not find container DN %s" % container_dn, e)
519 # Update existing GPlinks or Add new one
520 existing_gplink = False
521 if 'gPLink' in msg:
522 gplist = parse_gplink(msg['gPLink'][0])
523 existing_gplink = True
524 found = False
525 for g in gplist:
526 if g['dn'].lower() == gpo_dn.lower():
527 g['options'] = gplink_options
528 found = True
529 break
530 if not found:
531 gplist.insert(0, { 'dn' : gpo_dn, 'options' : gplink_options })
532 else:
533 gplist = []
534 gplist.append({ 'dn' : gpo_dn, 'options' : gplink_options })
536 gplink_str = encode_gplink(gplist)
538 m = ldb.Message()
539 m.dn = ldb.Dn(self.samdb, container_dn)
541 if existing_gplink:
542 m['new_value'] = ldb.MessageElement(gplink_str, ldb.FLAG_MOD_REPLACE, 'gPLink')
543 else:
544 m['new_value'] = ldb.MessageElement(gplink_str, ldb.FLAG_MOD_ADD, 'gPLink')
546 try:
547 self.samdb.modify(m)
548 except Exception, e:
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' ]
568 takes_options = [
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,
573 versionopts=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)
580 samdb_connect(self)
582 # Check if valid GPO
583 try:
584 msg = get_gpo_info(self.sambdb, gpo=gpo)[0]
585 except Exception, e:
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
590 try:
591 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
592 expression="(objectClass=*)",
593 attrs=['gPlink'])[0]
594 except Exception, e:
595 raise CommandError("Could not find container DN %s" % dn, e)
597 if 'gPLink' in msg:
598 gplist = parse_gplink(msg['gPLink'][0])
599 for g in gplist:
600 if g['dn'].lower() == gpo_dn.lower():
601 gplist.remove(g)
602 break
603 else:
604 raise CommandError("Specified GPO is not linked to this container")
606 m = ldb.Message()
607 m.dn = ldb.Dn(self.samdb, container_dn)
609 if gplist:
610 gplink_str = encode_gplink(gplist)
611 m['new_value'] = ldb.MessageElement(gplink_str, ldb.FLAG_MOD_REPLACE, 'gPLink')
612 else:
613 m['new_value'] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, 'gPLink')
615 try:
616 self.samdb.modify(m)
617 except Exception, e:
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' ]
637 takes_options = [
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,
642 versionopts=None):
644 self.url = H
645 self.lp = sambaopts.get_loadparm()
647 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
649 samdb_connect(self)
651 try:
652 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
653 expression="(objectClass=*)",
654 attrs=['gPOptions'])[0]
655 except Exception, e:
656 raise CommandError("Could not find Container DN %s" % container_dn, e)
658 inheritance = 0
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")
664 else:
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' ]
681 takes_options = [
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,
686 versionopts=None):
688 if inherit_state.lower() == 'block':
689 inheritance = dsdb.GPO_BLOCK_INHERITANCE
690 elif inherit_state.lower() == 'inherit':
691 inheritance = dsdb.GPO_INHERIT
692 else:
693 raise CommandError("Unknown inheritance state (%s)" % inherit_state)
695 self.url = H
696 self.lp = sambaopts.get_loadparm()
698 self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
700 samdb_connect(self)
702 try:
703 msg = self.samdb.search(base=container_dn, scope=ldb.SCOPE_BASE,
704 expression="(objectClass=*)",
705 attrs=['gPOptions'])[0]
706 except Exception, e:
707 raise CommandError("Could not find Container DN %s" % container_dn, e)
709 m = ldb.Message()
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')
714 else:
715 m['new_value'] = ldb.MessageElement(str(inheritance), ldb.FLAG_MOD_ADD, 'gPOptions')
717 try:
718 self.samdb.modify(m)
719 except Exception, e:
720 raise CommandError("Error setting inheritance state %s" % inherit_state, e)
723 class cmd_fetch(Command):
724 """Download a GPO"""
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' ]
736 takes_options = [
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)
749 samdb_connect(self)
750 try:
751 msg = get_gpo_info(self.samdb, gpo)[0]
752 except Exception, e:
753 raise CommandError("GPO %s does not exist" % gpo)
755 # verify UNC path
756 unc = msg['gPCFileSysPath'][0]
757 try:
758 [dom_name, service, sharepath] = parse_unc(unc)
759 except ValueError:
760 raise CommandError("Invalid GPO path (%s)" % unc)
762 # SMB connect to DC
763 try:
764 conn = smb.SMB(dc_hostname, service, lp=self.lp, creds=self.creds)
765 except Exception, e:
766 raise CommandError("Error connecting to '%s' using SMB" % dc_hostname, e)
768 # Copy GPT
769 if tmpdir is None:
770 tmpdir = "/tmp"
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):
776 os.mkdir(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)
782 try:
783 os.mkdir(gpodir)
784 copy_directory_remote_to_local(conn, sharepath, gpodir)
785 except Exception, e:
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' ]
803 takes_options = [
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,
809 versionopts=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)
817 samdb_connect(self)
819 msg = get_gpo_info(self.samdb, displayname=displayname)
820 if msg.count > 0:
821 raise CommandError("A GPO already existing with name '%s'" % displayname)
823 # Create new GUID
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)
829 # Create GPT
830 if tmpdir is None:
831 tmpdir = "/tmp"
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):
837 os.mkdir(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)
843 try:
844 os.mkdir(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)
849 except Exception, e:
850 raise CommandError("Error Creating GPO files", e)
852 # Add cn=<guid>
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))
857 m = ldb.Message()
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")
866 try:
867 self.samdb.add(m)
868 except Exception, e:
869 raise CommandError("Error adding GPO in AD", e)
871 # Add cn=User,cn=<guid>
872 child_dn = gpo_dn
873 child_dn.add_child(ldb.Dn(self.samdb, "CN=User"))
875 m = ldb.Message()
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")
879 try:
880 self.samdb.add(m)
881 except Exception, e:
882 raise CommandError("Error adding GPO in AD", e)
884 # Add cn=User,cn=<guid>
885 child_dn = gpo_dn
886 child_dn.add_child(ldb.Dn(self.samdb, "CN=Machine"))
888 m = ldb.Message()
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")
892 try:
893 self.samdb.add(m)
894 except Exception, e:
895 raise CommandError("Error adding GPO in AD", e)
897 # Copy GPO files over SMB
898 [dom_name, service, sharepath] = parse_unc(unc_path)
899 try:
900 conn = smb.SMB(dc_hostname, service, lp=self.lp, creds=self.creds)
901 except Exception, e:
902 raise CommandError("Error connecting to '%s' using SMB" % dc_hostname, e)
904 try:
905 create_directory_hier(conn, sharepath)
906 copy_directory_local_to_remote(conn, gpodir, sharepath)
907 except Exception, e:
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
922 # Copy sacl
923 fs_sd.sacl = ds_sd.sacl
925 # Copy dacl
926 dacl = ds_sd.dacl
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):
931 continue
933 # Copy the ace from the directory server security descriptor
934 new_ace = ace
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)
948 # Set ACL
949 try:
950 conn.set_acl(sharepath, fs_sd)
951 except Exception, e:
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"""
960 subcommands = {}
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()