3 # Copyright Matthias Dieter Wallnoefer 2009
4 # Copyright Andrew Kroeger 2009
5 # Copyright Jelmer Vernooij 2007-2012
6 # Copyright Giampaolo Lauria 2011
7 # Copyright Matthieu Patou <mat@matws.net> 2011
8 # Copyright Andrew Bartlett 2008
9 # Copyright Stefan Metzmacher 2012
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 samba.getopt as options
32 from samba.net import Net, LIBNET_JOIN_AUTOMATIC
34 from samba.join import join_RODC, join_DC, join_subdomain
35 from samba.auth import system_session
36 from samba.samdb import SamDB
37 from samba.dcerpc import drsuapi
38 from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX, DOMAIN_PASSWORD_STORE_CLEARTEXT
39 from samba.netcmd import (
45 from samba.netcmd.common import netcmd_get_domain_infos_via_cldap
46 from samba.samba3 import Samba3
47 from samba.samba3 import param as s3param
48 from samba.upgrade import upgrade_from_samba3
49 from samba.drs_utils import (
50 sendDsReplicaSync, drsuapi_connect, drsException,
54 from samba.dsdb import (
55 DS_DOMAIN_FUNCTION_2000,
56 DS_DOMAIN_FUNCTION_2003,
57 DS_DOMAIN_FUNCTION_2003_MIXED,
58 DS_DOMAIN_FUNCTION_2008,
59 DS_DOMAIN_FUNCTION_2008_R2,
60 DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL,
61 DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL,
62 UF_WORKSTATION_TRUST_ACCOUNT,
63 UF_SERVER_TRUST_ACCOUNT,
64 UF_TRUSTED_FOR_DELEGATION
67 from samba.credentials import DONT_USE_KERBEROS
68 from samba.provision import (
76 def get_testparm_var(testparm, smbconf, varname):
77 cmd = "%s -s -l --parameter-name='%s' %s 2>/dev/null" % (testparm, varname, smbconf)
78 output = os.popen(cmd, 'r').readline()
83 class cmd_domain_export_keytab(Command):
84 """Dump Kerberos keys of the domain into a keytab."""
86 synopsis = "%prog <keytab> [options]"
88 takes_optiongroups = {
89 "sambaopts": options.SambaOptions,
90 "credopts": options.CredentialsOptions,
91 "versionopts": options.VersionOptions,
95 Option("--principal", help="extract only this principal", type=str),
98 takes_args = ["keytab"]
100 def run(self, keytab, credopts=None, sambaopts=None, versionopts=None, principal=None):
101 lp = sambaopts.get_loadparm()
103 net.export_keytab(keytab=keytab, principal=principal)
105 cmd_domain_export_keytab = None
108 class cmd_domain_info(Command):
109 """Print basic info about a domain and the DC passed as parameter."""
111 synopsis = "%prog <ip_address> [options]"
116 takes_optiongroups = {
117 "sambaopts": options.SambaOptions,
118 "credopts": options.CredentialsOptions,
119 "versionopts": options.VersionOptions,
122 takes_args = ["address"]
124 def run(self, address, credopts=None, sambaopts=None, versionopts=None):
125 lp = sambaopts.get_loadparm()
127 res = netcmd_get_domain_infos_via_cldap(lp, None, address)
129 raise CommandError("Invalid IP address '" + address + "'!")
130 self.outf.write("Forest : %s\n" % res.forest)
131 self.outf.write("Domain : %s\n" % res.dns_domain)
132 self.outf.write("Netbios domain : %s\n" % res.domain_name)
133 self.outf.write("DC name : %s\n" % res.pdc_dns_name)
134 self.outf.write("DC netbios name : %s\n" % res.pdc_name)
135 self.outf.write("Server site : %s\n" % res.server_site)
136 self.outf.write("Client site : %s\n" % res.client_site)
139 class cmd_domain_provision(Command):
140 """Provision a domain."""
142 synopsis = "%prog [options]"
144 takes_optiongroups = {
145 "sambaopts": options.SambaOptions,
146 "versionopts": options.VersionOptions,
147 "credopts": options.CredentialsOptions,
151 Option("--interactive", help="Ask for names", action="store_true"),
152 Option("--domain", type="string", metavar="DOMAIN",
154 Option("--domain-guid", type="string", metavar="GUID",
155 help="set domainguid (otherwise random)"),
156 Option("--domain-sid", type="string", metavar="SID",
157 help="set domainsid (otherwise random)"),
158 Option("--ntds-guid", type="string", metavar="GUID",
159 help="set NTDS object GUID (otherwise random)"),
160 Option("--invocationid", type="string", metavar="GUID",
161 help="set invocationid (otherwise random)"),
162 Option("--host-name", type="string", metavar="HOSTNAME",
163 help="set hostname"),
164 Option("--host-ip", type="string", metavar="IPADDRESS",
165 help="set IPv4 ipaddress"),
166 Option("--host-ip6", type="string", metavar="IP6ADDRESS",
167 help="set IPv6 ipaddress"),
168 Option("--adminpass", type="string", metavar="PASSWORD",
169 help="choose admin password (otherwise random)"),
170 Option("--krbtgtpass", type="string", metavar="PASSWORD",
171 help="choose krbtgt password (otherwise random)"),
172 Option("--machinepass", type="string", metavar="PASSWORD",
173 help="choose machine password (otherwise random)"),
174 Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
175 choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"],
176 help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
177 "BIND9_FLATFILE uses bind9 text database to store zone information, "
178 "BIND9_DLZ uses samba4 AD to store zone information, "
179 "NONE skips the DNS setup entirely (not recommended)",
180 default="SAMBA_INTERNAL"),
181 Option("--dnspass", type="string", metavar="PASSWORD",
182 help="choose dns password (otherwise random)"),
183 Option("--ldapadminpass", type="string", metavar="PASSWORD",
184 help="choose password to set between Samba and it's LDAP backend (otherwise random)"),
185 Option("--root", type="string", metavar="USERNAME",
186 help="choose 'root' unix username"),
187 Option("--nobody", type="string", metavar="USERNAME",
188 help="choose 'nobody' user"),
189 Option("--wheel", type="string", metavar="GROUPNAME",
190 help="choose 'wheel' privileged group"),
191 Option("--users", type="string", metavar="GROUPNAME",
192 help="choose 'users' group"),
193 Option("--quiet", help="Be quiet", action="store_true"),
194 Option("--blank", action="store_true",
195 help="do not add users or groups, just the structure"),
196 Option("--ldap-backend-type", type="choice", metavar="LDAP-BACKEND-TYPE",
197 help="Test initialisation support for unsupported LDAP backend type (fedora-ds or openldap) DO NOT USE",
198 choices=["fedora-ds", "openldap"]),
199 Option("--server-role", type="choice", metavar="ROLE",
200 choices=["domain controller", "dc", "member server", "member", "standalone"],
201 help="The server role (domain controller | dc | member server | member | standalone). Default is dc.",
202 default="domain controller"),
203 Option("--function-level", type="choice", metavar="FOR-FUN-LEVEL",
204 choices=["2000", "2003", "2008", "2008_R2"],
205 help="The domain and forest function level (2000 | 2003 | 2008 | 2008_R2 - always native). Default is (Windows) 2003 Native.",
207 Option("--next-rid", type="int", metavar="NEXTRID", default=1000,
208 help="The initial nextRid value (only needed for upgrades). Default is 1000."),
209 Option("--partitions-only",
210 help="Configure Samba's partitions, but do not modify them (ie, join a BDC)", action="store_true"),
211 Option("--targetdir", type="string", metavar="DIR",
212 help="Set target directory"),
213 Option("--ol-mmr-urls", type="string", metavar="LDAPSERVER",
214 help="List of LDAP-URLS [ ldap://<FQHN>:<PORT>/ (where <PORT> has to be different than 389!) ] separated with comma (\",\") for use with OpenLDAP-MMR (Multi-Master-Replication), e.g.: \"ldap://s4dc1:9000,ldap://s4dc2:9000\""),
215 Option("--use-xattrs", type="choice", choices=["yes", "no", "auto"], help="Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities", default="auto"),
216 Option("--use-ntvfs", action="store_true", help="Use NTVFS for the fileserver (default = no)"),
217 Option("--use-rfc2307", action="store_true", help="Use AD to store posix attributes (default = no)"),
221 def run(self, sambaopts=None, credopts=None, versionopts=None,
244 ldap_backend_type=None,
248 partitions_only=None,
255 self.logger = self.get_logger("provision")
257 self.logger.setLevel(logging.WARNING)
259 self.logger.setLevel(logging.INFO)
261 lp = sambaopts.get_loadparm()
262 smbconf = lp.configfile
264 creds = credopts.get_credentials(lp)
266 creds.set_kerberos_state(DONT_USE_KERBEROS)
268 if dns_forwarder is not None:
269 suggested_forwarder = dns_forwarder
271 suggested_forwarder = self._get_nameserver_ip()
272 if suggested_forwarder is None:
273 suggested_forwarder = "none"
275 if len(self.raw_argv) == 1:
279 from getpass import getpass
282 def ask(prompt, default=None):
283 if default is not None:
284 print "%s [%s]: " % (prompt, default),
286 print "%s: " % (prompt,),
287 return sys.stdin.readline().rstrip("\n") or default
290 default = socket.getfqdn().split(".", 1)[1].upper()
293 realm = ask("Realm", default)
294 if realm in (None, ""):
295 raise CommandError("No realm set!")
298 default = realm.split(".")[0]
301 domain = ask("Domain", default)
303 raise CommandError("No domain set!")
305 server_role = ask("Server Role (dc, member, standalone)", "dc")
307 dns_backend = ask("DNS backend (SAMBA_INTERNAL, BIND9_FLATFILE, BIND9_DLZ, NONE)", "SAMBA_INTERNAL")
308 if dns_backend in (None, ''):
309 raise CommandError("No DNS backend set!")
311 if dns_backend == "SAMBA_INTERNAL":
312 dns_forwarder = ask("DNS forwarder IP address (write 'none' to disable forwarding)", suggested_forwarder)
313 if dns_forwarder.lower() in (None, 'none'):
314 suggested_forwarder = None
318 adminpassplain = getpass("Administrator password: ")
319 if not adminpassplain:
320 self.errf.write("Invalid administrator password.\n")
322 adminpassverify = getpass("Retype password: ")
323 if not adminpassplain == adminpassverify:
324 self.errf.write("Sorry, passwords do not match.\n")
326 adminpass = adminpassplain
330 realm = sambaopts._lp.get('realm')
332 raise CommandError("No realm set!")
334 raise CommandError("No domain set!")
337 self.logger.info("Administrator password will be set randomly!")
339 if function_level == "2000":
340 dom_for_fun_level = DS_DOMAIN_FUNCTION_2000
341 elif function_level == "2003":
342 dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
343 elif function_level == "2008":
344 dom_for_fun_level = DS_DOMAIN_FUNCTION_2008
345 elif function_level == "2008_R2":
346 dom_for_fun_level = DS_DOMAIN_FUNCTION_2008_R2
348 if dns_backend == "SAMBA_INTERNAL" and dns_forwarder is None:
349 dns_forwarder = suggested_forwarder
351 samdb_fill = FILL_FULL
353 samdb_fill = FILL_NT4SYNC
354 elif partitions_only:
355 samdb_fill = FILL_DRS
357 if targetdir is not None:
358 if not os.path.isdir(targetdir):
363 if use_xattrs == "yes":
365 elif use_xattrs == "auto" and not lp.get("posix:eadb"):
367 file = tempfile.NamedTemporaryFile(dir=os.path.abspath(targetdir))
369 file = tempfile.NamedTemporaryFile(dir=os.path.abspath(os.path.dirname(lp.get("private dir"))))
372 samba.ntacls.setntacl(lp, file.name,
373 "O:S-1-5-32G:S-1-5-32", "S-1-5-32", "native")
376 self.logger.info("You are not root or your system do not support xattr, using tdb backend for attributes. ")
381 self.logger.info("not using extended attributes to store ACLs and other metadata. If you intend to use this provision in production, rerun the script as root on a system supporting xattrs.")
383 session = system_session()
385 result = provision(self.logger,
386 session, creds, smbconf=smbconf, targetdir=targetdir,
387 samdb_fill=samdb_fill, realm=realm, domain=domain,
388 domainguid=domain_guid, domainsid=domain_sid,
390 hostip=host_ip, hostip6=host_ip6,
392 invocationid=invocationid, adminpass=adminpass,
393 krbtgtpass=krbtgtpass, machinepass=machinepass,
394 dns_backend=dns_backend, dns_forwarder=dns_forwarder,
395 dnspass=dnspass, root=root, nobody=nobody,
396 wheel=wheel, users=users,
397 serverrole=server_role, dom_for_fun_level=dom_for_fun_level,
398 backend_type=ldap_backend_type,
399 ldapadminpass=ldapadminpass, ol_mmr_urls=ol_mmr_urls,
400 useeadb=eadb, next_rid=next_rid, lp=lp, use_ntvfs=use_ntvfs,
401 use_rfc2307=use_rfc2307, skip_sysvolacl=False)
402 except ProvisioningError, e:
403 raise CommandError("Provision failed", e)
405 result.report_logger(self.logger)
407 def _get_nameserver_ip(self):
408 """Grab the nameserver IP address from /etc/resolv.conf."""
410 RESOLV_CONF="/etc/resolv.conf"
412 if not path.isfile(RESOLV_CONF):
413 self.logger.warning("Failed to locate %s" % RESOLV_CONF)
418 handle = open(RESOLV_CONF, 'r')
420 if not line.startswith('nameserver'):
422 # we want the last non-space continuous string of the line
423 return line.strip().split()[-1]
425 if handle is not None:
428 self.logger.warning("No nameserver found in %s" % RESOLV_CONF)
431 class cmd_domain_dcpromo(Command):
432 """Promote an existing domain member or NT4 PDC to an AD DC."""
434 synopsis = "%prog <dnsdomain> [DC|RODC] [options]"
436 takes_optiongroups = {
437 "sambaopts": options.SambaOptions,
438 "versionopts": options.VersionOptions,
439 "credopts": options.CredentialsOptions,
443 Option("--server", help="DC to join", type=str),
444 Option("--site", help="site to join", type=str),
445 Option("--targetdir", help="where to store provision", type=str),
446 Option("--domain-critical-only",
447 help="only replicate critical domain objects",
448 action="store_true"),
449 Option("--machinepass", type=str, metavar="PASSWORD",
450 help="choose machine password (otherwise random)"),
451 Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
452 action="store_true"),
453 Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
454 choices=["SAMBA_INTERNAL", "BIND9_DLZ", "NONE"],
455 help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
456 "BIND9_DLZ uses samba4 AD to store zone information, "
457 "NONE skips the DNS setup entirely (this DC will not be a DNS server)",
458 default="SAMBA_INTERNAL")
461 takes_args = ["domain", "role?"]
463 def run(self, domain, role=None, sambaopts=None, credopts=None,
464 versionopts=None, server=None, site=None, targetdir=None,
465 domain_critical_only=False, parent_domain=None, machinepass=None,
466 use_ntvfs=False, dns_backend=None):
467 lp = sambaopts.get_loadparm()
468 creds = credopts.get_credentials(lp)
469 net = Net(creds, lp, server=credopts.ipaddress)
472 site = "Default-First-Site-Name"
474 netbios_name = lp.get("netbios name")
480 join_DC(server=server, creds=creds, lp=lp, domain=domain,
481 site=site, netbios_name=netbios_name, targetdir=targetdir,
482 domain_critical_only=domain_critical_only,
483 machinepass=machinepass, use_ntvfs=use_ntvfs,
484 dns_backend=dns_backend,
485 promote_existing=True)
487 join_RODC(server=server, creds=creds, lp=lp, domain=domain,
488 site=site, netbios_name=netbios_name, targetdir=targetdir,
489 domain_critical_only=domain_critical_only,
490 machinepass=machinepass, use_ntvfs=use_ntvfs, dns_backend=dns_backend,
491 promote_existing=True)
493 raise CommandError("Invalid role '%s' (possible values: DC, RODC)" % role)
496 class cmd_domain_join(Command):
497 """Join domain as either member or backup domain controller."""
499 synopsis = "%prog <dnsdomain> [DC|RODC|MEMBER|SUBDOMAIN] [options]"
501 takes_optiongroups = {
502 "sambaopts": options.SambaOptions,
503 "versionopts": options.VersionOptions,
504 "credopts": options.CredentialsOptions,
508 Option("--server", help="DC to join", type=str),
509 Option("--site", help="site to join", type=str),
510 Option("--targetdir", help="where to store provision", type=str),
511 Option("--parent-domain", help="parent domain to create subdomain under", type=str),
512 Option("--domain-critical-only",
513 help="only replicate critical domain objects",
514 action="store_true"),
515 Option("--machinepass", type=str, metavar="PASSWORD",
516 help="choose machine password (otherwise random)"),
517 Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
518 action="store_true"),
519 Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
520 choices=["SAMBA_INTERNAL", "BIND9_DLZ", "NONE"],
521 help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
522 "BIND9_DLZ uses samba4 AD to store zone information, "
523 "NONE skips the DNS setup entirely (this DC will not be a DNS server)",
524 default="SAMBA_INTERNAL")
527 takes_args = ["domain", "role?"]
529 def run(self, domain, role=None, sambaopts=None, credopts=None,
530 versionopts=None, server=None, site=None, targetdir=None,
531 domain_critical_only=False, parent_domain=None, machinepass=None,
532 use_ntvfs=False, dns_backend=None):
533 lp = sambaopts.get_loadparm()
534 creds = credopts.get_credentials(lp)
535 net = Net(creds, lp, server=credopts.ipaddress)
538 site = "Default-First-Site-Name"
540 netbios_name = lp.get("netbios name")
545 if role is None or role == "MEMBER":
546 (join_password, sid, domain_name) = net.join_member(
547 domain, netbios_name, LIBNET_JOIN_AUTOMATIC,
548 machinepass=machinepass)
550 self.errf.write("Joined domain %s (%s)\n" % (domain_name, sid))
552 join_DC(server=server, creds=creds, lp=lp, domain=domain,
553 site=site, netbios_name=netbios_name, targetdir=targetdir,
554 domain_critical_only=domain_critical_only,
555 machinepass=machinepass, use_ntvfs=use_ntvfs, dns_backend=dns_backend)
557 join_RODC(server=server, creds=creds, lp=lp, domain=domain,
558 site=site, netbios_name=netbios_name, targetdir=targetdir,
559 domain_critical_only=domain_critical_only,
560 machinepass=machinepass, use_ntvfs=use_ntvfs,
561 dns_backend=dns_backend)
562 elif role == "SUBDOMAIN":
563 netbios_domain = lp.get("workgroup")
564 if parent_domain is None:
565 parent_domain = ".".join(domain.split(".")[1:])
566 join_subdomain(server=server, creds=creds, lp=lp, dnsdomain=domain,
567 parent_domain=parent_domain, site=site,
568 netbios_name=netbios_name, netbios_domain=netbios_domain,
569 targetdir=targetdir, machinepass=machinepass,
570 use_ntvfs=use_ntvfs, dns_backend=dns_backend)
572 raise CommandError("Invalid role '%s' (possible values: MEMBER, DC, RODC, SUBDOMAIN)" % role)
575 class cmd_domain_demote(Command):
576 """Demote ourselves from the role of Domain Controller."""
578 synopsis = "%prog [options]"
581 Option("--server", help="DC to force replication before demote", type=str),
582 Option("--targetdir", help="where provision is stored", type=str),
585 takes_optiongroups = {
586 "sambaopts": options.SambaOptions,
587 "credopts": options.CredentialsOptions,
588 "versionopts": options.VersionOptions,
591 def run(self, sambaopts=None, credopts=None,
592 versionopts=None, server=None, targetdir=None):
593 lp = sambaopts.get_loadparm()
594 creds = credopts.get_credentials(lp)
595 net = Net(creds, lp, server=credopts.ipaddress)
597 netbios_name = lp.get("netbios name")
598 samdb = SamDB(session_info=system_session(), credentials=creds, lp=lp)
600 res = samdb.search(expression='(&(objectClass=computer)(serverReferenceBL=*))', attrs=["dnsHostName", "name"])
602 raise CommandError("Unable to search for servers")
605 raise CommandError("You are the latest server in the domain")
609 if str(e["name"]).lower() != netbios_name.lower():
610 server = e["dnsHostName"]
613 ntds_guid = samdb.get_ntds_GUID()
614 msg = samdb.search(base=str(samdb.get_config_basedn()),
615 scope=ldb.SCOPE_SUBTREE, expression="(objectGUID=%s)" % ntds_guid,
617 if len(msg) == 0 or "options" not in msg[0]:
618 raise CommandError("Failed to find options on %s" % ntds_guid)
621 dsa_options = int(str(msg[0]['options']))
623 res = samdb.search(expression="(fSMORoleOwner=%s)" % str(ntds_dn),
624 controls=["search_options:1:2"])
627 raise CommandError("Current DC is still the owner of %d role(s), use the role command to transfer roles to another DC" % len(res))
629 self.errf.write("Using %s as partner server for the demotion\n" %
631 (drsuapiBind, drsuapi_handle, supportedExtensions) = drsuapi_connect(server, lp, creds)
633 self.errf.write("Desactivating inbound replication\n")
638 dsa_options |= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
639 nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
642 if not (dsa_options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL) and not samdb.am_rodc():
644 self.errf.write("Asking partner server %s to synchronize from us\n"
646 for part in (samdb.get_schema_basedn(),
647 samdb.get_config_basedn(),
648 samdb.get_root_basedn()):
650 sendDsReplicaSync(drsuapiBind, drsuapi_handle, ntds_guid, str(part), drsuapi.DRSUAPI_DRS_WRIT_REP)
651 except drsException, e:
653 "Error while demoting, "
654 "re-enabling inbound replication\n")
655 dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
656 nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
658 raise CommandError("Error while sending a DsReplicaSync for partion %s" % str(part), e)
660 remote_samdb = SamDB(url="ldap://%s" % server,
661 session_info=system_session(),
662 credentials=creds, lp=lp)
664 self.errf.write("Changing userControl and container\n")
665 res = remote_samdb.search(base=str(remote_samdb.get_root_basedn()),
666 expression="(&(objectClass=user)(sAMAccountName=%s$))" %
667 netbios_name.upper(),
668 attrs=["userAccountControl"])
670 uac = int(str(res[0]["userAccountControl"]))
674 "Error while demoting, re-enabling inbound replication\n")
675 dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
676 nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
678 raise CommandError("Error while changing account control", e)
682 "Error while demoting, re-enabling inbound replication")
683 dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
684 nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
686 raise CommandError("Unable to find object with samaccountName = %s$"
687 " in the remote dc" % netbios_name.upper())
691 uac ^= (UF_SERVER_TRUST_ACCOUNT|UF_TRUSTED_FOR_DELEGATION)
692 uac |= UF_WORKSTATION_TRUST_ACCOUNT
697 msg["userAccountControl"] = ldb.MessageElement("%d" % uac,
698 ldb.FLAG_MOD_REPLACE,
699 "userAccountControl")
701 remote_samdb.modify(msg)
704 "Error while demoting, re-enabling inbound replication")
705 dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
706 nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
709 raise CommandError("Error while changing account control", e)
711 parent = msg.dn.parent()
713 rdn = string.replace(rdn, ",%s" % str(parent), "")
714 # Let's move to the Computer container
718 computer_dn = ldb.Dn(remote_samdb, "CN=Computers,%s" % str(remote_samdb.get_root_basedn()))
719 res = remote_samdb.search(base=computer_dn, expression=rdn, scope=ldb.SCOPE_ONELEVEL)
722 res = remote_samdb.search(base=computer_dn, expression="%s-%d" % (rdn, i),
723 scope=ldb.SCOPE_ONELEVEL)
724 while(len(res) != 0 and i < 100):
726 res = remote_samdb.search(base=computer_dn, expression="%s-%d" % (rdn, i),
727 scope=ldb.SCOPE_ONELEVEL)
731 "Error while demoting, re-enabling inbound replication\n")
732 dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
733 nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
739 msg["userAccountControl"] = ldb.MessageElement("%d" % uac,
740 ldb.FLAG_MOD_REPLACE,
741 "userAccountControl")
743 remote_samdb.modify(msg)
745 raise CommandError("Unable to find a slot for renaming %s,"
746 " all names from %s-1 to %s-%d seemed used" %
747 (str(dc_dn), rdn, rdn, i - 9))
749 newrdn = "%s-%d" % (rdn, i)
752 newdn = ldb.Dn(remote_samdb, "%s,%s" % (newrdn, str(computer_dn)))
753 remote_samdb.rename(dc_dn, newdn)
756 "Error while demoting, re-enabling inbound replication\n")
757 dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
758 nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
764 msg["userAccountControl"] = ldb.MessageElement("%d" % uac,
765 ldb.FLAG_MOD_REPLACE,
766 "userAccountControl")
768 remote_samdb.modify(msg)
769 raise CommandError("Error while renaming %s to %s" % (str(dc_dn), str(newdn)), e)
772 server_dsa_dn = samdb.get_serverName()
773 domain = remote_samdb.get_root_basedn()
776 sendRemoveDsServer(drsuapiBind, drsuapi_handle, server_dsa_dn, domain)
777 except drsException, e:
779 "Error while demoting, re-enabling inbound replication\n")
780 dsa_options ^= DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
781 nmsg["options"] = ldb.MessageElement(str(dsa_options), ldb.FLAG_MOD_REPLACE, "options")
787 msg["userAccountControl"] = ldb.MessageElement("%d" % uac,
788 ldb.FLAG_MOD_REPLACE,
789 "userAccountControl")
791 remote_samdb.modify(msg)
792 remote_samdb.rename(newdn, dc_dn)
793 raise CommandError("Error while sending a removeDsServer", e)
795 for s in ("CN=Entreprise,CN=Microsoft System Volumes,CN=System,CN=Configuration",
796 "CN=%s,CN=Microsoft System Volumes,CN=System,CN=Configuration" % lp.get("realm"),
797 "CN=Domain System Volumes (SYSVOL share),CN=File Replication Service,CN=System"):
799 remote_samdb.delete(ldb.Dn(remote_samdb,
800 "%s,%s,%s" % (str(rdn), s, str(remote_samdb.get_root_basedn()))))
801 except ldb.LdbError, l:
804 for s in ("CN=Entreprise,CN=NTFRS Subscriptions",
805 "CN=%s, CN=NTFRS Subscriptions" % lp.get("realm"),
806 "CN=Domain system Volumes (SYSVOL Share), CN=NTFRS Subscriptions",
807 "CN=NTFRS Subscriptions"):
809 remote_samdb.delete(ldb.Dn(remote_samdb,
810 "%s,%s" % (s, str(newdn))))
811 except ldb.LdbError, l:
814 self.errf.write("Demote successfull\n")
817 class cmd_domain_level(Command):
818 """Raise domain and forest function levels."""
820 synopsis = "%prog (show|raise <options>) [options]"
822 takes_optiongroups = {
823 "sambaopts": options.SambaOptions,
824 "credopts": options.CredentialsOptions,
825 "versionopts": options.VersionOptions,
829 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
830 metavar="URL", dest="H"),
831 Option("--quiet", help="Be quiet", action="store_true"),
832 Option("--forest-level", type="choice", choices=["2003", "2008", "2008_R2"],
833 help="The forest function level (2003 | 2008 | 2008_R2)"),
834 Option("--domain-level", type="choice", choices=["2003", "2008", "2008_R2"],
835 help="The domain function level (2003 | 2008 | 2008_R2)")
838 takes_args = ["subcommand"]
840 def run(self, subcommand, H=None, forest_level=None, domain_level=None,
841 quiet=False, credopts=None, sambaopts=None, versionopts=None):
842 lp = sambaopts.get_loadparm()
843 creds = credopts.get_credentials(lp, fallback_machine=True)
845 samdb = SamDB(url=H, session_info=system_session(),
846 credentials=creds, lp=lp)
848 domain_dn = samdb.domain_dn()
850 res_forest = samdb.search("CN=Partitions,%s" % samdb.get_config_basedn(),
851 scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"])
852 assert len(res_forest) == 1
854 res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
855 attrs=["msDS-Behavior-Version", "nTMixedDomain"])
856 assert len(res_domain) == 1
858 res_dc_s = samdb.search("CN=Sites,%s" % samdb.get_config_basedn(),
859 scope=ldb.SCOPE_SUBTREE, expression="(objectClass=nTDSDSA)",
860 attrs=["msDS-Behavior-Version"])
861 assert len(res_dc_s) >= 1
864 level_forest = int(res_forest[0]["msDS-Behavior-Version"][0])
865 level_domain = int(res_domain[0]["msDS-Behavior-Version"][0])
866 level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0])
868 min_level_dc = int(res_dc_s[0]["msDS-Behavior-Version"][0]) # Init value
870 if int(msg["msDS-Behavior-Version"][0]) < min_level_dc:
871 min_level_dc = int(msg["msDS-Behavior-Version"][0])
873 if level_forest < 0 or level_domain < 0:
874 raise CommandError("Domain and/or forest function level(s) is/are invalid. Correct them or reprovision!")
876 raise CommandError("Lowest function level of a DC is invalid. Correct this or reprovision!")
877 if level_forest > level_domain:
878 raise CommandError("Forest function level is higher than the domain level(s). Correct this or reprovision!")
879 if level_domain > min_level_dc:
880 raise CommandError("Domain function level is higher than the lowest function level of a DC. Correct this or reprovision!")
883 raise CommandError("Could not retrieve the actual domain, forest level and/or lowest DC function level!")
885 if subcommand == "show":
886 self.message("Domain and forest function level for domain '%s'" % domain_dn)
887 if level_forest == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
888 self.message("\nATTENTION: You run SAMBA 4 on a forest function level lower than Windows 2000 (Native). This isn't supported! Please raise!")
889 if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
890 self.message("\nATTENTION: You run SAMBA 4 on a domain function level lower than Windows 2000 (Native). This isn't supported! Please raise!")
891 if min_level_dc == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
892 self.message("\nATTENTION: You run SAMBA 4 on a lowest function level of a DC lower than Windows 2003. This isn't supported! Please step-up or upgrade the concerning DC(s)!")
896 if level_forest == DS_DOMAIN_FUNCTION_2000:
898 elif level_forest == DS_DOMAIN_FUNCTION_2003_MIXED:
899 outstr = "2003 with mixed domains/interim (NT4 DC support)"
900 elif level_forest == DS_DOMAIN_FUNCTION_2003:
902 elif level_forest == DS_DOMAIN_FUNCTION_2008:
904 elif level_forest == DS_DOMAIN_FUNCTION_2008_R2:
907 outstr = "higher than 2008 R2"
908 self.message("Forest function level: (Windows) " + outstr)
910 if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
911 outstr = "2000 mixed (NT4 DC support)"
912 elif level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed == 0:
914 elif level_domain == DS_DOMAIN_FUNCTION_2003_MIXED:
915 outstr = "2003 with mixed domains/interim (NT4 DC support)"
916 elif level_domain == DS_DOMAIN_FUNCTION_2003:
918 elif level_domain == DS_DOMAIN_FUNCTION_2008:
920 elif level_domain == DS_DOMAIN_FUNCTION_2008_R2:
923 outstr = "higher than 2008 R2"
924 self.message("Domain function level: (Windows) " + outstr)
926 if min_level_dc == DS_DOMAIN_FUNCTION_2000:
928 elif min_level_dc == DS_DOMAIN_FUNCTION_2003:
930 elif min_level_dc == DS_DOMAIN_FUNCTION_2008:
932 elif min_level_dc == DS_DOMAIN_FUNCTION_2008_R2:
935 outstr = "higher than 2008 R2"
936 self.message("Lowest function level of a DC: (Windows) " + outstr)
938 elif subcommand == "raise":
941 if domain_level is not None:
942 if domain_level == "2003":
943 new_level_domain = DS_DOMAIN_FUNCTION_2003
944 elif domain_level == "2008":
945 new_level_domain = DS_DOMAIN_FUNCTION_2008
946 elif domain_level == "2008_R2":
947 new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
949 if new_level_domain <= level_domain and level_domain_mixed == 0:
950 raise CommandError("Domain function level can't be smaller than or equal to the actual one!")
952 if new_level_domain > min_level_dc:
953 raise CommandError("Domain function level can't be higher than the lowest function level of a DC!")
955 # Deactivate mixed/interim domain support
956 if level_domain_mixed != 0:
957 # Directly on the base DN
959 m.dn = ldb.Dn(samdb, domain_dn)
960 m["nTMixedDomain"] = ldb.MessageElement("0",
961 ldb.FLAG_MOD_REPLACE, "nTMixedDomain")
965 m.dn = ldb.Dn(samdb, "CN=" + lp.get("workgroup") + ",CN=Partitions,%s" % samdb.get_config_basedn())
966 m["nTMixedDomain"] = ldb.MessageElement("0",
967 ldb.FLAG_MOD_REPLACE, "nTMixedDomain")
970 except ldb.LdbError, (enum, emsg):
971 if enum != ldb.ERR_UNWILLING_TO_PERFORM:
974 # Directly on the base DN
976 m.dn = ldb.Dn(samdb, domain_dn)
977 m["msDS-Behavior-Version"]= ldb.MessageElement(
978 str(new_level_domain), ldb.FLAG_MOD_REPLACE,
979 "msDS-Behavior-Version")
983 m.dn = ldb.Dn(samdb, "CN=" + lp.get("workgroup")
984 + ",CN=Partitions,%s" % samdb.get_config_basedn())
985 m["msDS-Behavior-Version"]= ldb.MessageElement(
986 str(new_level_domain), ldb.FLAG_MOD_REPLACE,
987 "msDS-Behavior-Version")
990 except ldb.LdbError, (enum, emsg):
991 if enum != ldb.ERR_UNWILLING_TO_PERFORM:
994 level_domain = new_level_domain
995 msgs.append("Domain function level changed!")
997 if forest_level is not None:
998 if forest_level == "2003":
999 new_level_forest = DS_DOMAIN_FUNCTION_2003
1000 elif forest_level == "2008":
1001 new_level_forest = DS_DOMAIN_FUNCTION_2008
1002 elif forest_level == "2008_R2":
1003 new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
1004 if new_level_forest <= level_forest:
1005 raise CommandError("Forest function level can't be smaller than or equal to the actual one!")
1006 if new_level_forest > level_domain:
1007 raise CommandError("Forest function level can't be higher than the domain function level(s). Please raise it/them first!")
1009 m.dn = ldb.Dn(samdb, "CN=Partitions,%s" % samdb.get_config_basedn())
1010 m["msDS-Behavior-Version"]= ldb.MessageElement(
1011 str(new_level_forest), ldb.FLAG_MOD_REPLACE,
1012 "msDS-Behavior-Version")
1014 msgs.append("Forest function level changed!")
1015 msgs.append("All changes applied successfully!")
1016 self.message("\n".join(msgs))
1018 raise CommandError("invalid argument: '%s' (choose from 'show', 'raise')" % subcommand)
1021 class cmd_domain_passwordsettings(Command):
1022 """Set password settings.
1024 Password complexity, history length, minimum password length, the minimum
1025 and maximum password age) on a Samba4 server.
1028 synopsis = "%prog (show|set <options>) [options]"
1030 takes_optiongroups = {
1031 "sambaopts": options.SambaOptions,
1032 "versionopts": options.VersionOptions,
1033 "credopts": options.CredentialsOptions,
1037 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
1038 metavar="URL", dest="H"),
1039 Option("--quiet", help="Be quiet", action="store_true"),
1040 Option("--complexity", type="choice", choices=["on","off","default"],
1041 help="The password complexity (on | off | default). Default is 'on'"),
1042 Option("--store-plaintext", type="choice", choices=["on","off","default"],
1043 help="Store plaintext passwords where account have 'store passwords with reversible encryption' set (on | off | default). Default is 'off'"),
1044 Option("--history-length",
1045 help="The password history length (<integer> | default). Default is 24.", type=str),
1046 Option("--min-pwd-length",
1047 help="The minimum password length (<integer> | default). Default is 7.", type=str),
1048 Option("--min-pwd-age",
1049 help="The minimum password age (<integer in days> | default). Default is 1.", type=str),
1050 Option("--max-pwd-age",
1051 help="The maximum password age (<integer in days> | default). Default is 43.", type=str),
1054 takes_args = ["subcommand"]
1056 def run(self, subcommand, H=None, min_pwd_age=None, max_pwd_age=None,
1057 quiet=False, complexity=None, store_plaintext=None, history_length=None,
1058 min_pwd_length=None, credopts=None, sambaopts=None,
1060 lp = sambaopts.get_loadparm()
1061 creds = credopts.get_credentials(lp)
1063 samdb = SamDB(url=H, session_info=system_session(),
1064 credentials=creds, lp=lp)
1066 domain_dn = samdb.domain_dn()
1067 res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
1068 attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength",
1069 "minPwdAge", "maxPwdAge"])
1070 assert(len(res) == 1)
1072 pwd_props = int(res[0]["pwdProperties"][0])
1073 pwd_hist_len = int(res[0]["pwdHistoryLength"][0])
1074 cur_min_pwd_len = int(res[0]["minPwdLength"][0])
1076 cur_min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24))
1077 if int(res[0]["maxPwdAge"][0]) == -0x8000000000000000:
1080 cur_max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24))
1081 except Exception, e:
1082 raise CommandError("Could not retrieve password properties!", e)
1084 if subcommand == "show":
1085 self.message("Password informations for domain '%s'" % domain_dn)
1087 if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0:
1088 self.message("Password complexity: on")
1090 self.message("Password complexity: off")
1091 if pwd_props & DOMAIN_PASSWORD_STORE_CLEARTEXT != 0:
1092 self.message("Store plaintext passwords: on")
1094 self.message("Store plaintext passwords: off")
1095 self.message("Password history length: %d" % pwd_hist_len)
1096 self.message("Minimum password length: %d" % cur_min_pwd_len)
1097 self.message("Minimum password age (days): %d" % cur_min_pwd_age)
1098 self.message("Maximum password age (days): %d" % cur_max_pwd_age)
1099 elif subcommand == "set":
1102 m.dn = ldb.Dn(samdb, domain_dn)
1104 if complexity is not None:
1105 if complexity == "on" or complexity == "default":
1106 pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
1107 msgs.append("Password complexity activated!")
1108 elif complexity == "off":
1109 pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX)
1110 msgs.append("Password complexity deactivated!")
1112 if store_plaintext is not None:
1113 if store_plaintext == "on" or store_plaintext == "default":
1114 pwd_props = pwd_props | DOMAIN_PASSWORD_STORE_CLEARTEXT
1115 msgs.append("Plaintext password storage for changed passwords activated!")
1116 elif store_plaintext == "off":
1117 pwd_props = pwd_props & (~DOMAIN_PASSWORD_STORE_CLEARTEXT)
1118 msgs.append("Plaintext password storage for changed passwords deactivated!")
1120 if complexity is not None or store_plaintext is not None:
1121 m["pwdProperties"] = ldb.MessageElement(str(pwd_props),
1122 ldb.FLAG_MOD_REPLACE, "pwdProperties")
1124 if history_length is not None:
1125 if history_length == "default":
1128 pwd_hist_len = int(history_length)
1130 if pwd_hist_len < 0 or pwd_hist_len > 24:
1131 raise CommandError("Password history length must be in the range of 0 to 24!")
1133 m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len),
1134 ldb.FLAG_MOD_REPLACE, "pwdHistoryLength")
1135 msgs.append("Password history length changed!")
1137 if min_pwd_length is not None:
1138 if min_pwd_length == "default":
1141 min_pwd_len = int(min_pwd_length)
1143 if min_pwd_len < 0 or min_pwd_len > 14:
1144 raise CommandError("Minimum password length must be in the range of 0 to 14!")
1146 m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len),
1147 ldb.FLAG_MOD_REPLACE, "minPwdLength")
1148 msgs.append("Minimum password length changed!")
1150 if min_pwd_age is not None:
1151 if min_pwd_age == "default":
1154 min_pwd_age = int(min_pwd_age)
1156 if min_pwd_age < 0 or min_pwd_age > 998:
1157 raise CommandError("Minimum password age must be in the range of 0 to 998!")
1160 min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7))
1162 m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks),
1163 ldb.FLAG_MOD_REPLACE, "minPwdAge")
1164 msgs.append("Minimum password age changed!")
1166 if max_pwd_age is not None:
1167 if max_pwd_age == "default":
1170 max_pwd_age = int(max_pwd_age)
1172 if max_pwd_age < 0 or max_pwd_age > 999:
1173 raise CommandError("Maximum password age must be in the range of 0 to 999!")
1176 if max_pwd_age == 0:
1177 max_pwd_age_ticks = -0x8000000000000000
1179 max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7))
1181 m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks),
1182 ldb.FLAG_MOD_REPLACE, "maxPwdAge")
1183 msgs.append("Maximum password age changed!")
1185 if max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
1186 raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age))
1189 raise CommandError("You must specify at least one option to set. Try --help")
1191 msgs.append("All changes applied successfully!")
1192 self.message("\n".join(msgs))
1194 raise CommandError("Wrong argument '%s'!" % subcommand)
1197 class cmd_domain_classicupgrade(Command):
1198 """Upgrade from Samba classic (NT4-like) database to Samba AD DC database.
1200 Specify either a directory with all Samba classic DC databases and state files (with --dbdir) or
1201 the testparm utility from your classic installation (with --testparm).
1204 synopsis = "%prog [options] <classic_smb_conf>"
1206 takes_optiongroups = {
1207 "sambaopts": options.SambaOptions,
1208 "versionopts": options.VersionOptions
1212 Option("--dbdir", type="string", metavar="DIR",
1213 help="Path to samba classic DC database directory"),
1214 Option("--testparm", type="string", metavar="PATH",
1215 help="Path to samba classic DC testparm utility from the previous installation. This allows the default paths of the previous installation to be followed"),
1216 Option("--targetdir", type="string", metavar="DIR",
1217 help="Path prefix where the new Samba 4.0 AD domain should be initialised"),
1218 Option("--quiet", help="Be quiet", action="store_true"),
1219 Option("--verbose", help="Be verbose", action="store_true"),
1220 Option("--use-xattrs", type="choice", choices=["yes","no","auto"], metavar="[yes|no|auto]",
1221 help="Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities", default="auto"),
1222 Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
1223 action="store_true"),
1224 Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
1225 choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"],
1226 help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
1227 "BIND9_FLATFILE uses bind9 text database to store zone information, "
1228 "BIND9_DLZ uses samba4 AD to store zone information, "
1229 "NONE skips the DNS setup entirely (this DC will not be a DNS server)",
1230 default="SAMBA_INTERNAL")
1233 takes_args = ["smbconf"]
1235 def run(self, smbconf=None, targetdir=None, dbdir=None, testparm=None,
1236 quiet=False, verbose=False, use_xattrs=None, sambaopts=None, versionopts=None,
1237 dns_backend=None, use_ntvfs=False):
1239 if not os.path.exists(smbconf):
1240 raise CommandError("File %s does not exist" % smbconf)
1242 if testparm and not os.path.exists(testparm):
1243 raise CommandError("Testparm utility %s does not exist" % testparm)
1245 if dbdir and not os.path.exists(dbdir):
1246 raise CommandError("Directory %s does not exist" % dbdir)
1248 if not dbdir and not testparm:
1249 raise CommandError("Please specify either dbdir or testparm")
1251 logger = self.get_logger()
1253 logger.setLevel(logging.DEBUG)
1255 logger.setLevel(logging.WARNING)
1257 logger.setLevel(logging.INFO)
1259 if dbdir and testparm:
1260 logger.warning("both dbdir and testparm specified, ignoring dbdir.")
1263 lp = sambaopts.get_loadparm()
1265 s3conf = s3param.get_context()
1268 s3conf.set("realm", sambaopts.realm)
1270 if targetdir is not None:
1271 if not os.path.isdir(targetdir):
1275 if use_xattrs == "yes":
1277 elif use_xattrs == "auto" and not s3conf.get("posix:eadb"):
1279 tmpfile = tempfile.NamedTemporaryFile(dir=os.path.abspath(targetdir))
1281 tmpfile = tempfile.NamedTemporaryFile(dir=os.path.abspath(os.path.dirname(lp.get("private dir"))))
1284 samba.ntacls.setntacl(lp, tmpfile.name,
1285 "O:S-1-5-32G:S-1-5-32", "S-1-5-32", "native")
1288 # FIXME: Don't catch all exceptions here
1289 logger.info("You are not root or your system do not support xattr, using tdb backend for attributes. "
1290 "If you intend to use this provision in production, rerun the script as root on a system supporting xattrs.")
1294 # Set correct default values from dbdir or testparm
1297 paths["state directory"] = dbdir
1298 paths["private dir"] = dbdir
1299 paths["lock directory"] = dbdir
1300 paths["smb passwd file"] = dbdir + "/smbpasswd"
1302 paths["state directory"] = get_testparm_var(testparm, smbconf, "state directory")
1303 paths["private dir"] = get_testparm_var(testparm, smbconf, "private dir")
1304 paths["smb passwd file"] = get_testparm_var(testparm, smbconf, "smb passwd file")
1305 paths["lock directory"] = get_testparm_var(testparm, smbconf, "lock directory")
1306 # "testparm" from Samba 3 < 3.4.x is not aware of the parameter
1307 # "state directory", instead make use of "lock directory"
1308 if len(paths["state directory"]) == 0:
1309 paths["state directory"] = paths["lock directory"]
1312 s3conf.set(p, paths[p])
1314 # load smb.conf parameters
1315 logger.info("Reading smb.conf")
1316 s3conf.load(smbconf)
1317 samba3 = Samba3(smbconf, s3conf)
1319 logger.info("Provisioning")
1320 upgrade_from_samba3(samba3, logger, targetdir, session_info=system_session(),
1321 useeadb=eadb, dns_backend=dns_backend, use_ntvfs=use_ntvfs)
1324 class cmd_domain_samba3upgrade(cmd_domain_classicupgrade):
1325 __doc__ = cmd_domain_classicupgrade.__doc__
1327 # This command is present for backwards compatibility only,
1328 # and should not be shown.
1333 class cmd_domain(SuperCommand):
1334 """Domain management"""
1337 subcommands["demote"] = cmd_domain_demote()
1338 if cmd_domain_export_keytab is not None:
1339 subcommands["exportkeytab"] = cmd_domain_export_keytab()
1340 subcommands["info"] = cmd_domain_info()
1341 subcommands["provision"] = cmd_domain_provision()
1342 subcommands["join"] = cmd_domain_join()
1343 subcommands["dcpromo"] = cmd_domain_dcpromo()
1344 subcommands["level"] = cmd_domain_level()
1345 subcommands["passwordsettings"] = cmd_domain_passwordsettings()
1346 subcommands["classicupgrade"] = cmd_domain_classicupgrade()
1347 subcommands["samba3upgrade"] = cmd_domain_samba3upgrade()