samba-tool: Add functions to create directories and copy files over SMB share
[metze/samba/wip.git] / source4 / scripting / python / samba / netcmd / gpo.py
1 #!/usr/bin/env python
2 #
3 # implement samba_tool gpo commands
4 #
5 # Copyright Andrew Tridgell 2010
6 # Copyright Giampaolo Lauria 2011 <lauria2@yahoo.com>
7 # Copyright Amitay Isaacs 2011 <amitay@gmail.com>
8 #
9 # based on C implementation by Guenther Deschner and Wilco Baan Hofman
10 #
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.
15 #
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.
20 #
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/>.
23 #
24
25 import os
26 import samba.getopt as options
27 import ldb
28
29 from samba.auth import system_session
30 from samba.netcmd import (
31     Command,
32     CommandError,
33     Option,
34     SuperCommand,
35     )
36 from samba.samdb import SamDB
37 from samba import drs_utils, nttime2string, dsdb, dcerpc
38 from samba.dcerpc import misc
39 from samba.ndr import ndr_unpack
40 import samba.security
41 import samba.auth
42 from samba.auth import AUTH_SESSION_INFO_DEFAULT_GROUPS, AUTH_SESSION_INFO_AUTHENTICATED, AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
43 from samba.netcmd.common import netcmd_finddc
44 from samba import policy
45 from samba import smb
46
47
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)
56
57
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
63
64
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
73
74
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
83
84
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
97
98
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
105
106
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'''
110
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
119
120
121 def get_gpo_dn(samdb, gpo):
122     '''Construct the DN for gpo'''
123
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
128
129
130 def get_gpo_info(samdb, gpo=None, displayname=None, dn=None):
131     '''Get GPO information using gpo, displayname or dn'''
132
133     policies_dn = samdb.get_default_basedn()
134     policies_dn.add_child(ldb.Dn(samdb, "CN=Policies,CN=System"))
135
136     base_dn = policies_dn
137     search_expr = "(objectClass=groupPolicyContainer)"
138     search_scope = ldb.SCOPE_ONELEVEL
139
140     if gpo is not None:
141         search_expr = "(&(objectClass=groupPolicyContainer)(name=%s))" % ldb.binary_encode(gpo)
142
143     if displayname is not None:
144         search_expr = "(&(objectClass=groupPolicyContainer)(displayname=%s))" % ldb.binary_encode(displayname)
145
146     if dn is not None:
147         base_dn = dn
148         search_scope = ldb.SCOPE_BASE
149
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)
165
166     return msg
167
168
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         return []
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     return []
180
181
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()
190
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'])
195
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)
203
204
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()
213
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
218
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)
226
227
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)
235
236
237 class cmd_listall(Command):
238     """list all GPOs"""
239
240     synopsis = "%prog gpo listall [options]"
241
242     takes_options = [
243         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
244                metavar="URL", dest="H")
245         ]
246
247     def run(self, H=None, sambaopts=None, credopts=None, versionopts=None):
248
249         self.lp = sambaopts.get_loadparm()
250         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
251
252         self.url = dc_url(self.lp, self.creds, H)
253
254         samdb_connect(self)
255
256         msg = get_gpo_info(self.samdb, None)
257
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("")
266
267
268 class cmd_list(Command):
269     """list GPOs for an account"""
270
271     synopsis = "%prog gpo list <username> [options]"
272
273     takes_args = [ 'username' ]
274
275     takes_options = [
276         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
277                metavar="URL", dest="H")
278         ]
279
280     def run(self, username, H=None, sambaopts=None, credopts=None, versionopts=None):
281
282         self.lp = sambaopts.get_loadparm()
283         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
284
285         self.url = dc_url(self.lp, self.creds, H)
286
287         samdb_connect(self)
288
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)
295
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)
302
303         session_info_flags = ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
304                                AUTH_SESSION_INFO_AUTHENTICATED )
305
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
309
310         session = samba.auth.user_session(self.samdb, lp_ctx=self.lp, dn=user_dn,
311                                           session_info_flags=session_info_flags)
312
313         token = session.security_token
314
315         gpos = []
316
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
328
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
336
337                     secdesc_ndr = gmsg[0]['ntSecurityDescriptor'][0]
338                     secdesc = ndr_unpack(dcerpc.security.descriptor, secdesc_ndr)
339
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
348
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]))
356
357             # check if this blocks inheritance
358             gpoptions = int(attr_default(msg, 'gPOptions', 0))
359             if gpoptions & dsdb.GPO_BLOCK_INHERITANCE:
360                 inherit = False
361
362             if dn == self.samdb.get_default_basedn():
363                 break
364             dn = dn.parent()
365
366         if is_computer:
367             msg_str = 'computer'
368         else:
369             msg_str = 'user'
370
371         print("GPOs for %s %s" % (msg_str, username))
372         for g in gpos:
373             print("    %s %s" % (g[0], g[1]))
374
375
376 class cmd_show(Command):
377     """Show information for a GPO"""
378
379     synopsis = "%prog gpo show <gpo> [options]"
380
381     takes_optiongroups = {
382         "sambaopts": options.SambaOptions,
383         "versionopts": options.VersionOptions,
384         "credopts": options.CredentialsOptions,
385     }
386
387     takes_args = [ 'gpo' ]
388
389     takes_options = [
390         Option("-H", help="LDB URL for database or target server", type=str)
391         ]
392
393     def run(self, gpo, H=None, sambaopts=None, credopts=None, versionopts=None):
394
395         self.lp = sambaopts.get_loadparm()
396         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
397
398         self.url = dc_url(self.lp, self.creds, H)
399
400         samdb_connect(self)
401
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)
406
407         secdesc_ndr = msg['ntSecurityDescriptor'][0]
408         secdesc = ndr_unpack(dcerpc.security.descriptor, secdesc_ndr)
409
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("")
418
419
420 class cmd_getlink(Command):
421     """List GPO Links for a container"""
422
423     synopsis = "%prog gpo getlink <container_dn> [options]"
424
425     takes_optiongroups = {
426         "sambaopts": options.SambaOptions,
427         "versionopts": options.VersionOptions,
428         "credopts": options.CredentialsOptions,
429     }
430
431     takes_args = [ 'container_dn' ]
432
433     takes_options = [
434         Option("-H", help="LDB URL for database or target server", type=str)
435         ]
436
437     def run(self, container_dn, H=None, sambaopts=None, credopts=None,
438                 versionopts=None):
439
440         self.lp = sambaopts.get_loadparm()
441         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
442
443         self.url = dc_url(self.lp, self.creds, H)
444
445         samdb_connect(self)
446
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)
453
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)
465
466
467 class cmd_setlink(Command):
468     """Add or Update a GPO link to a container"""
469
470     synopsis = "%prog gpo setlink <container_dn> <gpo> [options]"
471
472     takes_optiongroups = {
473         "sambaopts": options.SambaOptions,
474         "versionopts": options.VersionOptions,
475         "credopts": options.CredentialsOptions,
476     }
477
478     takes_args = [ 'container_dn', 'gpo' ]
479
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")
486         ]
487
488     def run(self, container_dn, gpo, H=None, disabled=False, enforced=False,
489                 sambaopts=None, credopts=None, versionopts=None):
490
491         self.lp = sambaopts.get_loadparm()
492         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
493
494         self.url = dc_url(self.lp, self.creds, H)
495
496         samdb_connect(self)
497
498         gplink_options = 0
499         if disabled:
500             gplink_options |= dsdb.GPLINK_OPT_DISABLE
501         if enforced:
502             gplink_options |= dsdb.GPLINK_OPT_ENFORCE
503
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)
510
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)
518
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 })
535
536         gplink_str = encode_gplink(gplist)
537
538         m = ldb.Message()
539         m.dn = ldb.Dn(self.samdb, container_dn)
540
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')
545
546         try:
547             self.samdb.modify(m)
548         except Exception, e:
549             raise CommandError("Error adding GPO Link", e)
550
551         print("Added/Updated GPO link")
552         cmd_getlink().run(container_dn, H, sambaopts, credopts, versionopts)
553
554
555 class cmd_dellink(Command):
556     """Delete GPO link from a container"""
557
558     synopsis = "%prog gpo dellink <container_dn> <gpo> [options]"
559
560     takes_optiongroups = {
561         "sambaopts": options.SambaOptions,
562         "versionopts": options.VersionOptions,
563         "credopts": options.CredentialsOptions,
564     }
565
566     takes_args = [ 'container_dn', 'gpo' ]
567
568     takes_options = [
569         Option("-H", help="LDB URL for database or target server", type=str),
570         ]
571
572     def run(self, container_dn, gpo_dn, H=None, sambaopts=None, credopts=None,
573                 versionopts=None):
574
575         self.lp = sambaopts.get_loadparm()
576         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
577
578         self.url = dc_url(self.lp, self.creds, H)
579
580         samdb_connect(self)
581
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)
588
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)
596
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");
605
606         m = ldb.Message()
607         m.dn = ldb.Dn(self.samdb, container_dn)
608
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')
614
615         try:
616             self.samdb.modify(m)
617         except Exception, e:
618             raise CommandError("Error Removing GPO Link (%s)" % e)
619
620         print("Deleted GPO link.")
621         cmd_getlink().run(container_dn, H, sambaopts, credopts, versionopts)
622
623
624 class cmd_getinheritance(Command):
625     """Get inheritance flag for a container"""
626
627     synopsis = "%prog gpo getinheritance <container_dn> [options]"
628
629     takes_optiongroups = {
630         "sambaopts": options.SambaOptions,
631         "versionopts": options.VersionOptions,
632         "credopts": options.CredentialsOptions,
633     }
634
635     takes_args = [ 'container_dn' ]
636
637     takes_options = [
638         Option("-H", help="LDB URL for database or target server", type=str)
639         ]
640
641     def run(self, container_dn, H=None, sambaopts=None, credopts=None,
642                 versionopts=None):
643
644         self.url = H
645         self.lp = sambaopts.get_loadparm()
646
647         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
648
649         samdb_connect(self)
650
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)
657
658         inheritance = 0
659         if 'gPOptions' in msg:
660             inheritance = int(msg['gPOptions'][0]);
661
662         if inheritance == dsdb.GPO_BLOCK_INHERITANCE:
663             print("Container has GPO_BLOCK_INHERITANCE")
664         else:
665             print("Container has GPO_INHERIT")
666
667
668 class cmd_setinheritance(Command):
669     """Set inheritance flag on a container"""
670
671     synopsis = "%prog gpo setinheritance <container_dn> <block|inherit> [options]"
672
673     takes_optiongroups = {
674         "sambaopts": options.SambaOptions,
675         "versionopts": options.VersionOptions,
676         "credopts": options.CredentialsOptions,
677     }
678
679     takes_args = [ 'container_dn', 'inherit_state' ]
680
681     takes_options = [
682         Option("-H", help="LDB URL for database or target server", type=str)
683         ]
684
685     def run(self, container_dn, inherit_state, H=None, sambaopts=None, credopts=None,
686                 versionopts=None):
687
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)
694
695         self.url = H
696         self.lp = sambaopts.get_loadparm()
697
698         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
699
700         samdb_connect(self)
701
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)
708
709         m = ldb.Message()
710         m.dn = ldb.Dn(self.samdb, container_dn)
711
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');
716
717         try:
718             self.samdb.modify(m)
719         except Exception, e:
720             raise CommandError("Error setting inheritance state %s" % inherit_state, e)
721
722
723 class cmd_fetch(Command):
724     """Download a GPO"""
725
726     synopsis = "%prog gpo fetch <gpo> [options]"
727
728     takes_optiongroups = {
729         "sambaopts": options.SambaOptions,
730         "versionopts": options.VersionOptions,
731         "credopts": options.CredentialsOptions,
732     }
733
734     takes_args = [ 'gpo' ]
735
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)
739         ]
740
741     def run(self, gpo, H=None, tmpdir=None, sambaopts=None, credopts=None, versionopts=None):
742
743         self.lp = sambaopts.get_loadparm()
744         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
745
746         dc_hostname = netcmd_finddc(self.lp, self.creds)
747         self.url = dc_url(self.lp, self.creds, H, dc=dc_hostname)
748
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)
754
755         # verify UNC path
756         unc = msg['gPCFileSysPath'][0]
757         try:
758             [dom_name, service, sharepath] = parse_unc(unc)
759         except:
760             raise CommandError("Invalid GPO path (%s)" % unc)
761
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)
767
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)
773
774         localdir = os.path.join(tmpdir, "policy")
775         if not os.path.isdir(localdir):
776             os.mkdir(localdir)
777
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)
781
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)
788
789
790 class cmd_create(Command):
791     """Create a GPO"""
792
793 class cmd_setacl(Command):
794     """Set ACL on a GPO"""
795
796
797 class cmd_gpo(SuperCommand):
798     """Group Policy Object (GPO) commands"""
799
800     subcommands = {}
801     subcommands["listall"] = cmd_listall()
802     subcommands["list"] = cmd_list()
803     subcommands["show"] = cmd_show()
804     subcommands["getlink"] = cmd_getlink()
805     subcommands["setlink"] = cmd_setlink()
806     subcommands["dellink"] = cmd_dellink()
807     subcommands["getinheritance"] = cmd_getinheritance()
808     subcommands["setinheritance"] = cmd_setinheritance()
809     subcommands["fetch"] = cmd_fetch()
810     subcommands["create"] = cmd_create()
811     subcommands["setacl"] = cmd_setacl()