Exemplo n.º 1
0
class cmd_fsmo_transfer(Command):
    """Transfer the role."""

    synopsis = "%prog [options]"

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
        "versionopts": options.VersionOptions,
    }

    takes_options = [
        Option("-H",
               "--URL",
               help="LDB URL for database or target server",
               type=str,
               metavar="URL",
               dest="H"),
        Option("--role",
               type="choice",
               choices=[
                   "rid", "pdc", "infrastructure", "schema", "naming",
                   "domaindns", "forestdns", "all"
               ],
               help="""The FSMO role to seize or transfer.\n
rid=RidAllocationMasterRole\n
schema=SchemaMasterRole\n
pdc=PdcEmulationMasterRole\n
naming=DomainNamingMasterRole\n
infrastructure=InfrastructureMasterRole\n
domaindns=DomainDnsZonesMasterRole\n
forestdns=ForestDnsZonesMasterRole\n
all=all of the above\n
You must provide an Admin user and password."""),
    ]

    takes_args = []

    def run(self,
            force=None,
            H=None,
            role=None,
            credopts=None,
            sambaopts=None,
            versionopts=None):

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)

        samdb = SamDB(url=H,
                      session_info=system_session(),
                      credentials=creds,
                      lp=lp)

        if role == "all":
            transfer_role(self.outf, "rid", samdb)
            transfer_role(self.outf, "pdc", samdb)
            transfer_role(self.outf, "naming", samdb)
            transfer_role(self.outf, "infrastructure", samdb)
            transfer_role(self.outf, "schema", samdb)
            transfer_dns_role(self.outf, sambaopts, credopts, "domaindns",
                              samdb)
            transfer_dns_role(self.outf, sambaopts, credopts, "forestdns",
                              samdb)
        else:
            if role == "domaindns" or role == "forestdns":
                transfer_dns_role(self.outf, sambaopts, credopts, role, samdb)
            else:
                transfer_role(self.outf, role, samdb)
Exemplo n.º 2
0
class cmd_ldapcmp(Command):
    """Compare two ldap databases."""
    synopsis = "%prog <URL1> <URL2> (domain|configuration|schema|dnsdomain|dnsforest) [options]"

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions,
        "credopts": options.CredentialsOptionsDouble,
    }

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions,
        "credopts": options.CredentialsOptionsDouble,
    }

    takes_args = [
        "URL1", "URL2", "context1?", "context2?", "context3?", "context4?",
        "context5?"
    ]

    takes_options = [
        Option("-w",
               "--two",
               dest="two",
               action="store_true",
               default=False,
               help="Hosts are in two different domains"),
        Option("-q",
               "--quiet",
               dest="quiet",
               action="store_true",
               default=False,
               help="Do not print anything but relay on just exit code"),
        Option("-v",
               "--verbose",
               dest="verbose",
               action="store_true",
               default=False,
               help="Print all DN pairs that have been compared"),
        Option("--sd",
               dest="descriptor",
               action="store_true",
               default=False,
               help="Compare nTSecurityDescriptor attibutes only"),
        Option(
            "--sort-aces",
            dest="sort_aces",
            action="store_true",
            default=False,
            help="Sort ACEs before comparison of nTSecurityDescriptor attribute"
        ),
        Option(
            "--view",
            dest="view",
            default="section",
            help=
            "Display mode for nTSecurityDescriptor results. Possible values: section or collision."
        ),
        Option(
            "--base",
            dest="base",
            default="",
            help="Pass search base that will build DN list for the first DC."),
        Option(
            "--base2",
            dest="base2",
            default="",
            help=
            "Pass search base that will build DN list for the second DC. Used when --two or when compare two different DNs."
        ),
        Option(
            "--scope",
            dest="scope",
            default="SUB",
            help=
            "Pass search scope that builds DN list. Options: SUB, ONE, BASE"),
        Option(
            "--filter",
            dest="filter",
            default="",
            help=
            "List of comma separated attributes to ignore in the comparision"),
        Option(
            "--skip-missing-dn",
            dest="skip_missing_dn",
            action="store_true",
            default=False,
            help=
            "Skip report and failure due to missing DNs in one server or another"
        ),
    ]

    def run(self,
            URL1,
            URL2,
            context1=None,
            context2=None,
            context3=None,
            context4=None,
            context5=None,
            two=False,
            quiet=False,
            verbose=False,
            descriptor=False,
            sort_aces=False,
            view="section",
            base="",
            base2="",
            scope="SUB",
            filter="",
            credopts=None,
            sambaopts=None,
            versionopts=None,
            skip_missing_dn=False):

        lp = sambaopts.get_loadparm()

        using_ldap = URL1.startswith("ldap") or URL2.startswith("ldap")

        if using_ldap:
            creds = credopts.get_credentials(lp, fallback_machine=True)
        else:
            creds = None
        creds2 = credopts.get_credentials2(lp, guess=False)
        if creds2.is_anonymous():
            creds2 = creds
        else:
            creds2.set_domain("")
            creds2.set_workstation("")
        if using_ldap and not creds.authentication_requested():
            raise CommandError(
                "You must supply at least one username/password pair")

        # make a list of contexts to compare in
        contexts = []
        if context1 is None:
            if base and base2:
                # If search bases are specified context is defaulted to
                # DOMAIN so the given search bases can be verified.
                contexts = ["DOMAIN"]
            else:
                # if no argument given, we compare all contexts
                contexts = [
                    "DOMAIN", "CONFIGURATION", "SCHEMA", "DNSDOMAIN",
                    "DNSFOREST"
                ]
        else:
            for c in [context1, context2, context3, context4, context5]:
                if c is None:
                    continue
                if not c.upper() in [
                        "DOMAIN", "CONFIGURATION", "SCHEMA", "DNSDOMAIN",
                        "DNSFOREST"
                ]:
                    raise CommandError("Incorrect argument: %s" % c)
                contexts.append(c.upper())

        if verbose and quiet:
            raise CommandError("You cannot set --verbose and --quiet together")
        if (not base and base2) or (base and not base2):
            raise CommandError(
                "You need to specify both --base and --base2 at the same time")
        if descriptor and view.upper() not in ["SECTION", "COLLISION"]:
            raise CommandError(
                "Invalid --view value. Choose from: section or collision")
        if not scope.upper() in ["SUB", "ONE", "BASE"]:
            raise CommandError(
                "Invalid --scope value. Choose from: SUB, ONE, BASE")

        con1 = LDAPBase(URL1,
                        creds,
                        lp,
                        two=two,
                        quiet=quiet,
                        descriptor=descriptor,
                        sort_aces=sort_aces,
                        verbose=verbose,
                        view=view,
                        base=base,
                        scope=scope,
                        outf=self.outf,
                        errf=self.errf)
        assert len(con1.base_dn) > 0

        con2 = LDAPBase(URL2,
                        creds2,
                        lp,
                        two=two,
                        quiet=quiet,
                        descriptor=descriptor,
                        sort_aces=sort_aces,
                        verbose=verbose,
                        view=view,
                        base=base2,
                        scope=scope,
                        outf=self.outf,
                        errf=self.errf)
        assert len(con2.base_dn) > 0

        filter_list = filter.split(",")

        status = 0
        for context in contexts:
            if not quiet:
                self.outf.write("\n* Comparing [%s] context...\n" % context)

            b1 = LDAPBundel(con1,
                            context=context,
                            filter_list=filter_list,
                            outf=self.outf,
                            errf=self.errf)
            b2 = LDAPBundel(con2,
                            context=context,
                            filter_list=filter_list,
                            outf=self.outf,
                            errf=self.errf)

            if b1 == b2:
                if not quiet:
                    self.outf.write("\n* Result for [%s]: SUCCESS\n" % context)
            else:
                if not quiet:
                    self.outf.write("\n* Result for [%s]: FAILURE\n" % context)
                    if not descriptor:
                        assert len(b1.summary["df_value_attrs"]) == len(
                            b2.summary["df_value_attrs"])
                        b2.summary["df_value_attrs"] = []
                        self.outf.write("\nSUMMARY\n")
                        self.outf.write("---------\n")
                        b1.print_summary()
                        b2.print_summary()
                # mark exit status as FAILURE if a least one comparison failed
                status = -1
        if status != 0:
            raise CommandError("Compare failed: %d" % status)
Exemplo n.º 3
0
class cmd_fsmo_seize(Command):
    """Seize the role."""

    synopsis = "%prog [options]"

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
        "versionopts": options.VersionOptions,
    }

    takes_options = [
        Option("-H",
               "--URL",
               help="LDB URL for database or target server",
               type=str,
               metavar="URL",
               dest="H"),
        Option("--force",
               help="Force seizing of role without attempting to transfer.",
               action="store_true"),
        Option("--role",
               type="choice",
               choices=[
                   "rid", "pdc", "infrastructure", "schema", "naming",
                   "domaindns", "forestdns", "all"
               ],
               help="""The FSMO role to seize or transfer.\n
rid=RidAllocationMasterRole\n
schema=SchemaMasterRole\n
pdc=PdcEmulationMasterRole\n
naming=DomainNamingMasterRole\n
infrastructure=InfrastructureMasterRole\n
domaindns=DomainDnsZonesMasterRole\n
forestdns=ForestDnsZonesMasterRole\n
all=all of the above\n
You must provide an Admin user and password."""),
    ]

    takes_args = []

    def seize_role(self, role, samdb, force):
        """Seize standard fsmo role. """

        serviceName = samdb.get_dsServiceName()
        domain_dn = samdb.domain_dn()
        self.infrastructure_dn = "CN=Infrastructure," + domain_dn
        self.naming_dn = "CN=Partitions,%s" % samdb.get_config_basedn()
        self.schema_dn = str(samdb.get_schema_basedn())
        self.rid_dn = "CN=RID Manager$,CN=System," + domain_dn

        m = ldb.Message()
        if role == "rid":
            m.dn = ldb.Dn(samdb, self.rid_dn)
        elif role == "pdc":
            m.dn = ldb.Dn(samdb, domain_dn)
        elif role == "naming":
            m.dn = ldb.Dn(samdb, self.naming_dn)
        elif role == "infrastructure":
            m.dn = ldb.Dn(samdb, self.infrastructure_dn)
        elif role == "schema":
            m.dn = ldb.Dn(samdb, self.schema_dn)
        else:
            raise CommandError("Invalid FSMO role.")
        # first try to transfer to avoid problem if the owner is still active
        seize = False
        master_owner = get_fsmo_roleowner(samdb, m.dn, role)
        # if there is a different owner
        if master_owner is not None:
            # if there is a different owner
            if master_owner != serviceName:
                # if --force isn't given, attempt transfer
                if force is None:
                    self.message("Attempting transfer...")
                    try:
                        transfer_role(self.outf, role, samdb)
                    except:
                        # transfer failed, use the big axe...
                        seize = True
                        self.message("Transfer unsuccessful, seizing...")
                    else:
                        self.message("Transfer successful, not seizing role")
                        return True
            else:
                self.outf.write("This DC already has the '%s' FSMO role\n" %
                                role)
                return False
        else:
            seize = True

        if force is not None or seize:
            self.message("Seizing %s FSMO role..." % role)
            m["fSMORoleOwner"] = ldb.MessageElement(serviceName,
                                                    ldb.FLAG_MOD_REPLACE,
                                                    "fSMORoleOwner")

            samdb.transaction_start()
            try:
                samdb.modify(m)
                if role == "rid":
                    # We may need to allocate the initial RID Set
                    samdb.create_own_rid_set()

            except LdbError as e1:
                (num, msg) = e1.args
                if role == "rid" and num == ldb.ERR_ENTRY_ALREADY_EXISTS:

                    # Try again without the RID Set allocation
                    # (normal).  We have to manage the transaction as
                    # we do not have nested transactions and creating
                    # a RID set touches multiple objects. :-(
                    samdb.transaction_cancel()
                    samdb.transaction_start()
                    try:
                        samdb.modify(m)
                    except LdbError as e:
                        (num, msg) = e.args
                        samdb.transaction_cancel()
                        raise CommandError("Failed to seize '%s' role: %s" %
                                           (role, msg))

                else:
                    samdb.transaction_cancel()
                    raise CommandError("Failed to seize '%s' role: %s" %
                                       (role, msg))
            samdb.transaction_commit()
            self.outf.write("FSMO seize of '%s' role successful\n" % role)

            return True

    def seize_dns_role(self, role, samdb, credopts, sambaopts, versionopts,
                       force):
        """Seize DNS FSMO role. """

        serviceName = samdb.get_dsServiceName()
        domain_dn = samdb.domain_dn()
        forest_dn = samba.dn_from_dns_name(samdb.forest_dns_name())
        self.domaindns_dn = "CN=Infrastructure,DC=DomainDnsZones," + domain_dn
        self.forestdns_dn = "CN=Infrastructure,DC=ForestDnsZones," + forest_dn

        m = ldb.Message()
        if role == "domaindns":
            m.dn = ldb.Dn(samdb, self.domaindns_dn)
        elif role == "forestdns":
            m.dn = ldb.Dn(samdb, self.forestdns_dn)
        else:
            raise CommandError("Invalid FSMO role.")
        # first try to transfer to avoid problem if the owner is still active
        seize = False
        master_owner = get_fsmo_roleowner(samdb, m.dn, role)
        if master_owner is not None:
            # if there is a different owner
            if master_owner != serviceName:
                # if --force isn't given, attempt transfer
                if force is None:
                    self.message("Attempting transfer...")
                    try:
                        transfer_dns_role(self.outf, sambaopts, credopts, role,
                                          samdb)
                    except:
                        # transfer failed, use the big axe...
                        seize = True
                        self.message("Transfer unsuccessful, seizing...")
                    else:
                        self.message("Transfer successful, not seizing role\n")
                        return True
            else:
                self.outf.write("This DC already has the '%s' FSMO role\n" %
                                role)
                return False
        else:
            seize = True

        if force is not None or seize:
            self.message("Seizing %s FSMO role..." % role)
            m["fSMORoleOwner"] = ldb.MessageElement(serviceName,
                                                    ldb.FLAG_MOD_REPLACE,
                                                    "fSMORoleOwner")
            try:
                samdb.modify(m)
            except LdbError as e2:
                (num, msg) = e2.args
                raise CommandError("Failed to seize '%s' role: %s" %
                                   (role, msg))
            self.outf.write("FSMO seize of '%s' role successful\n" % role)
            return True

    def run(self,
            force=None,
            H=None,
            role=None,
            credopts=None,
            sambaopts=None,
            versionopts=None):

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)

        samdb = SamDB(url=H,
                      session_info=system_session(),
                      credentials=creds,
                      lp=lp)

        if role == "all":
            self.seize_role("rid", samdb, force)
            self.seize_role("pdc", samdb, force)
            self.seize_role("naming", samdb, force)
            self.seize_role("infrastructure", samdb, force)
            self.seize_role("schema", samdb, force)
            self.seize_dns_role("domaindns", samdb, credopts, sambaopts,
                                versionopts, force)
            self.seize_dns_role("forestdns", samdb, credopts, sambaopts,
                                versionopts, force)
        else:
            if role == "domaindns" or role == "forestdns":
                self.seize_dns_role(role, samdb, credopts, sambaopts,
                                    versionopts, force)
            else:
                self.seize_role(role, samdb, force)
Exemplo n.º 4
0
Arquivo: ou.py Projeto: wade1990/samba
class cmd_listobjects(Command):
    """List all objects in an organizational unit.

    The name of the organizational unit can be specified as a full DN
    or without the domainDN component.

    Examples:
    samba-tool ou listobjects 'OU=OrgUnit,DC=samdom,DC=example,DC=com'
    samba-tool ou listobjects 'OU=OrgUnit'

    The examples show how an administrator would list all child objects
    of the ou 'OrgUnit'.
    """
    synopsis = "%prog <ou_dn> [options]"

    takes_options = [
        Option("-H", "--URL", help="LDB URL for database or target server",
               type=str, metavar="URL", dest="H"),
        Option("--full-dn", dest="full_dn", default=False, action='store_true',
               help="Display DNs including the base DN."),
        Option("-r", "--recursive", dest="recursive", default=False,
               action='store_true', help="List objects recursively."),
    ]

    takes_args = ["ou_dn"]
    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
        "versionopts": options.VersionOptions,
    }

    def run(self, ou_dn, credopts=None, sambaopts=None, versionopts=None,
            H=None, full_dn=False, recursive=False):
        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)
        samdb = SamDB(url=H, session_info=system_session(),
                      credentials=creds, lp=lp)
        domain_dn = ldb.Dn(samdb, samdb.domain_dn())

        try:
            full_ou_dn = samdb.normalize_dn_in_domain(ou_dn)
        except Exception as e:
            raise CommandError('Invalid ou_dn "%s": %s' % (ou_dn, e))

        minchilds = 0
        scope = ldb.SCOPE_ONELEVEL
        if recursive:
            minchilds = 1
            scope = ldb.SCOPE_SUBTREE

        try:
            childs = samdb.search(base=full_ou_dn,
                                  expression="(objectclass=*)",
                                  scope=scope, attrs=[])
            if len(childs) <= minchilds:
                self.outf.write('ou "%s" is empty\n' % ou_dn)
                return

            for child in sorted(childs, key=attrgetter('dn')):
                if child.dn == full_ou_dn:
                    continue
                if not full_dn:
                    child.dn.remove_base_components(len(domain_dn))
                self.outf.write("%s\n" % child.dn)

        except Exception as e:
            raise CommandError('Failed to list contents of ou "%s"' %
                               full_ou_dn, e)
Exemplo n.º 5
0
Arquivo: ou.py Projeto: wade1990/samba
class cmd_move(Command):
    """Move an organizational unit.

    The name of the organizational units can be specified as a full DN
    or without the domainDN component.

    Examples:
    samba-tool ou move 'OU=OrgUnit,DC=samdom,DC=example,DC=com' \\
        'OU=NewParentOfOrgUnit,DC=samdom,DC=example,DC=com'
    samba-tool ou rename 'OU=OrgUnit' 'OU=NewParentOfOrgUnit'

    The examples show how an administrator would move an ou 'OrgUnit'
    into the ou 'NewParentOfOrgUnit'. The ou 'OrgUnit' would become
    a child of the 'NewParentOfOrgUnit' ou. The new DN would be
    'OU=OrgUnit,OU=NewParentOfOrgUnit,DC=samdom,DC=example,DC=com'
    """

    synopsis = "%prog <old_ou_dn> <new_parent_dn> [options]"

    takes_options = [
        Option("-H", "--URL", help="LDB URL for database or target server",
               type=str, metavar="URL", dest="H"),
    ]

    takes_args = ["old_ou_dn", "new_parent_dn"]
    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
        "versionopts": options.VersionOptions,
    }

    def run(self, old_ou_dn, new_parent_dn, credopts=None, sambaopts=None,
            versionopts=None, H=None):
        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)
        samdb = SamDB(url=H, session_info=system_session(),
                      credentials=creds, lp=lp)

        domain_dn = ldb.Dn(samdb, samdb.domain_dn())
        try:
            full_old_ou_dn = samdb.normalize_dn_in_domain(old_ou_dn)
        except Exception as e:
            raise CommandError('Invalid old_ou_dn "%s": %s' %
                               (old_ou_dn, e))
        try:
            full_new_parent_dn = samdb.normalize_dn_in_domain(new_parent_dn)
        except Exception as e:
            raise CommandError('Invalid new_parent_dn "%s": %s' %
                               (new_parent_dn, e))

        full_new_ou_dn = ldb.Dn(samdb, str(full_old_ou_dn))
        full_new_ou_dn.remove_base_components(len(full_old_ou_dn) - 1)
        full_new_ou_dn.add_base(full_new_parent_dn)

        try:
            res = samdb.search(base=full_old_ou_dn,
                               expression="(objectclass=organizationalUnit)",
                               scope=ldb.SCOPE_BASE, attrs=[])
            if len(res) == 0:
                self.outf.write('Unable to find ou "%s"\n' % full_old_ou_dn)
                return
            samdb.rename(full_old_ou_dn, full_new_ou_dn)
        except Exception as e:
            raise CommandError('Failed to move ou "%s"' % full_old_ou_dn, e)
        self.outf.write('Moved ou "%s" into "%s"\n' %
                        (full_old_ou_dn, full_new_parent_dn))
Exemplo n.º 6
0
class cmd_reps(GraphCommand):
    "repsFrom/repsTo from every DSA"

    takes_options = COMMON_OPTIONS + [
        Option("-p", "--partition", help="restrict to this partition",
               default=None),
    ]

    def run(self, H=None, output=None, shorten_names=False,
            key=True, talk_to_remote=False,
            sambaopts=None, credopts=None, versionopts=None,
            mode='self', partition=None, color=None, color_scheme=None,
            utf8=None, format=None):
        # We use the KCC libraries in readonly mode to get the
        # replication graph.
        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)
        local_kcc, dsas = self.get_kcc_and_dsas(H, lp, creds)
        unix_now = local_kcc.unix_now

        # Allow people to say "--partition=DOMAIN" rather than
        # "--partition=DC=blah,DC=..."
        short_partitions, long_partitions = get_partition_maps(local_kcc.samdb)
        if partition is not None:
            partition = short_partitions.get(partition.upper(), partition)
            if partition not in long_partitions:
                raise CommandError("unknown partition %s" % partition)

        # nc_reps is an autovivifying dictionary of dictionaries of lists.
        # nc_reps[partition]['current' | 'needed'] is a list of
        # (dsa dn string, repsFromTo object) pairs.
        nc_reps = defaultdict(lambda: defaultdict(list))

        guid_to_dnstr = {}

        # We run a new KCC for each DSA even if we aren't talking to
        # the remote, because after kcc.run (or kcc.list_dsas) the kcc
        # ends up in a messy state.
        for dsa_dn in dsas:
            kcc = KCC(unix_now, readonly=True)
            if talk_to_remote:
                res = local_kcc.samdb.search(dsa_dn,
                                             scope=SCOPE_BASE,
                                             attrs=["dNSHostName"])
                dns_name = res[0]["dNSHostName"][0]
                print("Attempting to contact ldap://%s (%s)" %
                      (dns_name, dsa_dn),
                      file=sys.stderr)
                try:
                    kcc.load_samdb("ldap://%s" % dns_name, lp, creds)
                except KCCError as e:
                    print("Could not contact ldap://%s (%s)" % (dns_name, e),
                          file=sys.stderr)
                    continue

                kcc.run(H, lp, creds)
            else:
                kcc.load_samdb(H, lp, creds)
                kcc.run(H, lp, creds, forced_local_dsa=dsa_dn)

            dsas_from_here = set(kcc.list_dsas())
            if dsas != dsas_from_here:
                print("found extra DSAs:", file=sys.stderr)
                for dsa in (dsas_from_here - dsas):
                    print("   %s" % dsa, file=sys.stderr)
                print("missing DSAs (known locally, not by %s):" % dsa_dn,
                      file=sys.stderr)
                for dsa in (dsas - dsas_from_here):
                    print("   %s" % dsa, file=sys.stderr)

            for remote_dn in dsas_from_here:
                if mode == 'others' and remote_dn == dsa_dn:
                    continue
                elif mode == 'self' and remote_dn != dsa_dn:
                    continue

                remote_dsa = kcc.get_dsa('CN=NTDS Settings,' + remote_dn)
                kcc.translate_ntdsconn(remote_dsa)
                guid_to_dnstr[str(remote_dsa.dsa_guid)] = remote_dn
                # get_reps_tables() returns two dictionaries mapping
                # dns to NCReplica objects
                c, n = remote_dsa.get_rep_tables()
                for part, rep in c.items():
                    if partition is None or part == partition:
                        nc_reps[part]['current'].append((dsa_dn, rep))
                for part, rep in n.items():
                    if partition is None or part == partition:
                        nc_reps[part]['needed'].append((dsa_dn, rep))

        all_edges = {'needed':  {'to': [], 'from': []},
                     'current': {'to': [], 'from': []}}

        for partname, part in nc_reps.items():
            for state, edgelists in all_edges.items():
                for dsa_dn, rep in part[state]:
                    short_name = long_partitions.get(partname, partname)
                    for r in rep.rep_repsFrom:
                        edgelists['from'].append(
                            (dsa_dn,
                             guid_to_dnstr[str(r.source_dsa_obj_guid)],
                             short_name))
                    for r in rep.rep_repsTo:
                        edgelists['to'].append(
                            (guid_to_dnstr[str(r.source_dsa_obj_guid)],
                             dsa_dn,
                             short_name))

        # Here we have the set of edges. From now it is a matter of
        # interpretation and presentation.

        if self.calc_output_format(format, output) == 'distance':
            color_scheme = self.calc_distance_color_scheme(color,
                                                           color_scheme,
                                                           output)
            header_strings = {
                'from': "RepsFrom objects for %s",
                'to': "RepsTo objects for %s",
            }
            for state, edgelists in all_edges.items():
                for direction, items in edgelists.items():
                    part_edges = defaultdict(list)
                    for src, dest, part in items:
                        part_edges[part].append((src, dest))
                    for part, edges in part_edges.items():
                        s = distance_matrix(None, edges,
                                            utf8=utf8,
                                            colour=color_scheme,
                                            shorten_names=shorten_names,
                                            generate_key=key)

                        s = "\n%s\n%s" % (header_strings[direction] % part, s)
                        self.write(s, output)
            return

        edge_colours = []
        edge_styles = []
        dot_edges = []
        dot_vertices = set()
        used_colours = {}
        key_set = set()
        for state, edgelist in all_edges.items():
            for direction, items in edgelist.items():
                for src, dest, part in items:
                    colour = used_colours.setdefault((part),
                                                     colour_hash((part,
                                                                  direction)))
                    linestyle = 'dotted' if state == 'needed' else 'solid'
                    arrow = 'open' if direction == 'to' else 'empty'
                    dot_vertices.add(src)
                    dot_vertices.add(dest)
                    dot_edges.append((src, dest))
                    edge_colours.append(colour)
                    style = 'style="%s"; arrowhead=%s' % (linestyle, arrow)
                    edge_styles.append(style)
                    key_set.add((part, 'reps' + direction.title(),
                                 colour, style))

        key_items = []
        if key:
            for part, direction, colour, linestyle in sorted(key_set):
                key_items.append((False,
                                  'color="%s"; %s' % (colour, linestyle),
                                  "%s %s" % (part, direction)))
            key_items.append((False,
                              'style="dotted"; arrowhead="open"',
                              "repsFromTo is needed"))
            key_items.append((False,
                              'style="solid"; arrowhead="open"',
                              "repsFromTo currently exists"))

        s = dot_graph(dot_vertices, dot_edges,
                      directed=True,
                      edge_colors=edge_colours,
                      edge_styles=edge_styles,
                      shorten_names=shorten_names,
                      key_items=key_items)

        self.write(s, output)
Exemplo n.º 7
0
class cmd_query(Command):
    """Query a name."""

    synopsis = '%prog <server> <zone> <name> <A|AAAA|CNAME|MX|NS|SOA|SRV|TXT|ALL> [options]'

    takes_args = [ 'server', 'zone', 'name', 'rtype' ]

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option('--authority', help='Search authoritative records (default)',
                action='store_true', dest='authority'),
        Option('--cache', help='Search cached records',
                action='store_true', dest='cache'),
        Option('--glue', help='Search glue records',
                action='store_true', dest='glue'),
        Option('--root', help='Search root hints',
                action='store_true', dest='root'),
        Option('--additional', help='List additional records',
                action='store_true', dest='additional'),
        Option('--no-children', help='Do not list children',
                action='store_true', dest='no_children'),
        Option('--only-children', help='List only children',
                action='store_true', dest='only_children')
    ]

    def run(self, server, zone, name, rtype, authority=False, cache=False,
            glue=False, root=False, additional=False, no_children=False,
            only_children=False, sambaopts=None, credopts=None,
            versionopts=None):
        record_type = dns_type_flag(rtype)

        select_flags = 0
        if authority:
            select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
        if cache:
            select_flags |= dnsserver.DNS_RPC_VIEW_CACHE_DATA
        if glue:
            select_flags |= dnsserver.DNS_RPC_VIEW_GLUE_DATA
        if root:
            select_flags |= dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA
        if additional:
            select_flags |= dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA
        if no_children:
            select_flags |= dnsserver.DNS_RPC_VIEW_NO_CHILDREN
        if only_children:
            select_flags |= dnsserver.DNS_RPC_VIEW_ONLY_CHILDREN

        if select_flags == 0:
            select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA

        if select_flags == dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA:
            self.outf.write('Specify either --authority or --root along with --additional.\n')
            self.outf.write('Assuming --authority.\n')
            select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA

        self.lp = sambaopts.get_loadparm()
        self.creds = credopts.get_credentials(self.lp)
        dns_conn = dns_connect(server, self.lp, self.creds)

        buflen, res = dns_conn.DnssrvEnumRecords2(
                dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, zone, name,
                None, record_type, select_flags, None, None)
        print_dnsrecords(self.outf, res)
Exemplo n.º 8
0
class cmd_domain_backup_offline(samba.netcmd.Command):
    '''Backup the local domain directories safely into a tar file.

    Takes a backup copy of the current domain from the local files on disk,
    with proper locking of the DB to ensure consistency. If the domain were to
    undergo a catastrophic failure, then the backup file can be used to recover
    the domain.

    An offline backup differs to an online backup in the following ways:
    - a backup can be created even if the DC isn't currently running.
    - includes non-replicated attributes that an online backup wouldn't store.
    - takes a copy of the raw database files, which has the risk that any
      hidden problems in the DB are preserved in the backup.'''

    synopsis = "%prog [options]"
    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
    }

    takes_options = [
        Option("--targetdir", help="Output directory (required)", type=str),
    ]

    backup_ext = '.bak-offline'

    def offline_tdb_copy(self, path):
        backup_path = path + self.backup_ext
        try:
            tdb_copy(path, backup_path, readonly=True)
        except CalledProcessError as copy_err:
            # If the copy didn't work, check if it was caused by an EINVAL
            # error on opening the DB.  If so, it's a mutex locked database,
            # which we can safely ignore.
            try:
                tdb.open(path)
            except Exception as e:
                if hasattr(e, 'errno') and e.errno == errno.EINVAL:
                    return
                raise e
            raise copy_err
        if not os.path.exists(backup_path):
            s = "tdbbackup said backup succeeded but {0} not found"
            raise CommandError(s.format(backup_path))

    def offline_mdb_copy(self, path):
        mdb_copy(path, path + self.backup_ext)

    # Secrets databases are a special case: a transaction must be started
    # on the secrets.ldb file before backing up that file and secrets.tdb
    def backup_secrets(self, private_dir, lp, logger):
        secrets_path = os.path.join(private_dir, 'secrets')
        secrets_obj = Ldb(secrets_path + '.ldb', lp=lp)
        logger.info('Starting transaction on ' + secrets_path)
        secrets_obj.transaction_start()
        self.offline_tdb_copy(secrets_path + '.ldb')
        self.offline_tdb_copy(secrets_path + '.tdb')
        secrets_obj.transaction_cancel()

    # sam.ldb must have a transaction started on it before backing up
    # everything in sam.ldb.d with the appropriate backup function.
    def backup_smb_dbs(self, private_dir, samdb, lp, logger):
        # First, determine if DB backend is MDB.  Assume not unless there is a
        # 'backendStore' attribute on @PARTITION containing the text 'mdb'
        store_label = "backendStore"
        res = samdb.search(base="@PARTITION",
                           scope=ldb.SCOPE_BASE,
                           attrs=[store_label])
        mdb_backend = store_label in res[0] and res[0][store_label][0] == 'mdb'

        sam_ldb_path = os.path.join(private_dir, 'sam.ldb')
        copy_function = None
        if mdb_backend:
            logger.info('MDB backend detected.  Using mdb backup function.')
            copy_function = self.offline_mdb_copy
        else:
            logger.info('Starting transaction on ' + sam_ldb_path)
            copy_function = self.offline_tdb_copy
            sam_obj = Ldb(sam_ldb_path, lp=lp)
            sam_obj.transaction_start()

        logger.info('   backing up ' + sam_ldb_path)
        self.offline_tdb_copy(sam_ldb_path)
        sam_ldb_d = sam_ldb_path + '.d'
        for sam_file in os.listdir(sam_ldb_d):
            sam_file = os.path.join(sam_ldb_d, sam_file)
            if sam_file.endswith('.ldb'):
                logger.info('   backing up locked/related file ' + sam_file)
                copy_function(sam_file)
            else:
                logger.info('   copying locked/related file ' + sam_file)
                shutil.copyfile(sam_file, sam_file + self.backup_ext)

        if not mdb_backend:
            sam_obj.transaction_cancel()

    # Find where a path should go in the fixed backup archive structure.
    def get_arc_path(self, path, conf_paths):
        backup_dirs = {
            "private": conf_paths.private_dir,
            "statedir": conf_paths.state_dir,
            "etc": os.path.dirname(conf_paths.smbconf)
        }
        matching_dirs = [(_, p) for (_, p) in backup_dirs.items()
                         if path.startswith(p)]
        arc_path, fs_path = matching_dirs[0]

        # If more than one directory is a parent of this path, then at least
        # one configured path is a subdir of another. Use closest match.
        if len(matching_dirs) > 1:
            arc_path, fs_path = max(matching_dirs, key=lambda p: len(p[1]))
        arc_path += path[len(fs_path):]

        return arc_path

    def run(self, sambaopts=None, targetdir=None):

        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG)
        logger.addHandler(logging.StreamHandler(sys.stdout))

        # Get the absolute paths of all the directories we're going to backup
        lp = sambaopts.get_loadparm()

        paths = samba.provision.provision_paths_from_lp(lp, lp.get('realm'))
        if not (paths.samdb and os.path.exists(paths.samdb)):
            raise CommandError('No sam.db found.  This backup ' +
                               'tool is only for AD DCs')

        check_targetdir(logger, targetdir)

        samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp)
        sid = get_sid_for_restore(samdb)

        backup_dirs = [
            paths.private_dir, paths.state_dir,
            os.path.dirname(paths.smbconf)
        ]  # etc dir
        logger.info('running backup on dirs: {0}'.format(
            ' '.join(backup_dirs)))

        # Recursively get all file paths in the backup directories
        all_files = []
        for backup_dir in backup_dirs:
            for (working_dir, _, filenames) in os.walk(backup_dir):
                if working_dir.startswith(paths.sysvol):
                    continue
                if working_dir.endswith('.sock') or '.sock/' in working_dir:
                    continue

                for filename in filenames:
                    if filename in all_files:
                        continue

                    # Assume existing backup files are from a previous backup.
                    # Delete and ignore.
                    if filename.endswith(self.backup_ext):
                        os.remove(os.path.join(working_dir, filename))
                        continue

                    # Sock files are autogenerated at runtime, ignore.
                    if filename.endswith('.sock'):
                        continue

                    all_files.append(os.path.join(working_dir, filename))

        # Backup secrets, sam.ldb and their downstream files
        self.backup_secrets(paths.private_dir, lp, logger)
        self.backup_smb_dbs(paths.private_dir, samdb, lp, logger)

        # Open the new backed up samdb, flag it as backed up, and write
        # the next SID so the restore tool can add objects.
        # WARNING: Don't change this code unless you know what you're doing.
        #          Writing to a .bak file only works because the DN being
        #          written to happens to be top level.
        samdb = SamDB(url=paths.samdb + self.backup_ext,
                      session_info=system_session(),
                      lp=lp)
        time_str = get_timestamp()
        add_backup_marker(samdb, "backupDate", time_str)
        add_backup_marker(samdb, "sidForRestore", sid)

        # Now handle all the LDB and TDB files that are not linked to
        # anything else.  Use transactions for LDBs.
        for path in all_files:
            if not os.path.exists(path + self.backup_ext):
                if path.endswith('.ldb'):
                    logger.info('Starting transaction on solo db: ' + path)
                    ldb_obj = Ldb(path, lp=lp)
                    ldb_obj.transaction_start()
                    logger.info('   running tdbbackup on the same file')
                    self.offline_tdb_copy(path)
                    ldb_obj.transaction_cancel()
                elif path.endswith('.tdb'):
                    logger.info('running tdbbackup on lone tdb file ' + path)
                    self.offline_tdb_copy(path)

        # Now make the backup tar file and add all
        # backed up files and any other files to it.
        temp_tar_dir = tempfile.mkdtemp(dir=targetdir,
                                        prefix='INCOMPLETEsambabackupfile')
        temp_tar_name = os.path.join(temp_tar_dir, "samba-backup.tar.bz2")
        tar = tarfile.open(temp_tar_name, 'w:bz2')

        logger.info('running offline ntacl backup of sysvol')
        sysvol_tar_fn = 'sysvol.tar.gz'
        sysvol_tar = os.path.join(temp_tar_dir, sysvol_tar_fn)
        backup_offline(paths.sysvol, sysvol_tar, samdb, paths.smbconf)
        tar.add(sysvol_tar, sysvol_tar_fn)
        os.remove(sysvol_tar)

        create_log_file(temp_tar_dir, lp, "offline", "localhost", True)
        backup_fn = os.path.join(temp_tar_dir, "backup.txt")
        tar.add(backup_fn, os.path.basename(backup_fn))
        os.remove(backup_fn)

        logger.info('building backup tar')
        for path in all_files:
            arc_path = self.get_arc_path(path, paths)

            if os.path.exists(path + self.backup_ext):
                logger.info('   adding backup ' + arc_path + self.backup_ext +
                            ' to tar and deleting file')
                tar.add(path + self.backup_ext, arcname=arc_path)
                os.remove(path + self.backup_ext)
            elif path.endswith('.ldb') or path.endswith('.tdb'):
                logger.info('   skipping ' + arc_path)
            else:
                logger.info('   adding misc file ' + arc_path)
                tar.add(path, arcname=arc_path)

        tar.close()
        os.rename(
            temp_tar_name,
            os.path.join(targetdir,
                         'samba-backup-{0}.tar.bz2'.format(time_str)))
        os.rmdir(temp_tar_dir)
        logger.info('Backup succeeded.')
Exemplo n.º 9
0
class cmd_zonelist(Command):
    """Query for zones."""

    synopsis = '%prog <server> [options]'

    takes_args = [ 'server' ]

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option('--client-version', help='Client Version',
                default='longhorn', metavar='w2k|dotnet|longhorn',
                choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
        Option('--primary', help='List primary zones (default)',
                action='store_true', dest='primary'),
        Option('--secondary', help='List secondary zones',
                action='store_true', dest='secondary'),
        Option('--cache', help='List cached zones',
                action='store_true', dest='cache'),
        Option('--auto', help='List automatically created zones',
                action='store_true', dest='auto'),
        Option('--forward', help='List forward zones',
                action='store_true', dest='forward'),
        Option('--reverse', help='List reverse zones',
                action='store_true', dest='reverse'),
        Option('--ds', help='List directory integrated zones',
                action='store_true', dest='ds'),
        Option('--non-ds', help='List non-directory zones',
                action='store_true', dest='nonds')
    ]

    def run(self, server, cli_ver, primary=False, secondary=False, cache=False,
                auto=False, forward=False, reverse=False, ds=False, nonds=False,
                sambaopts=None, credopts=None, versionopts=None):
        request_filter = 0

        if primary:
            request_filter |= dnsserver.DNS_ZONE_REQUEST_PRIMARY
        if secondary:
            request_filter |= dnsserver.DNS_ZONE_REQUEST_SECONDARY
        if cache:
            request_filter |= dnsserver.DNS_ZONE_REQUEST_CACHE
        if auto:
            request_filter |= dnsserver.DNS_ZONE_REQUEST_AUTO
        if forward:
            request_filter |= dnsserver.DNS_ZONE_REQUEST_FORWARD
        if reverse:
            request_filter |= dnsserver.DNS_ZONE_REQUEST_REVERSE
        if ds:
            request_filter |= dnsserver.DNS_ZONE_REQUEST_DS
        if nonds:
            request_filter |= dnsserver.DNS_ZONE_REQUEST_NON_DS

        if request_filter == 0:
            request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY

        self.lp = sambaopts.get_loadparm()
        self.creds = credopts.get_credentials(self.lp)
        dns_conn = dns_connect(server, self.lp, self.creds)

        client_version = dns_client_version(cli_ver)

        typeid, res = dns_conn.DnssrvComplexOperation2(client_version,
                                                        0, server, None,
                                                        'EnumZones',
                                                        dnsserver.DNSSRV_TYPEID_DWORD,
                                                        request_filter)

        if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
            typeid = dnsserver.DNSSRV_TYPEID_ZONE_W2K
        else:
            typeid = dnsserver.DNSSRV_TYPEID_ZONE
        print_enumzones(self.outf, typeid, res)
Exemplo n.º 10
0
class cmd_domain_backup_restore(cmd_fsmo_seize):
    '''Restore the domain's DB from a backup-file.

    This restores a previously backed up copy of the domain's DB on a new DC.

    Note that the restored DB will not contain the original DC that the backup
    was taken from (or any other DCs in the original domain). Only the new DC
    (specified by --newservername) will be present in the restored DB.

    Samba can then be started against the restored DB. Any existing DCs for the
    domain should be shutdown before the new DC is started. Other DCs can then
    be joined to the new DC to recover the network.

    Note that this command should be run as the root user - it will fail
    otherwise.'''

    synopsis = ("%prog --backup-file=<tar-file> --targetdir=<output-dir> "
                "--newservername=<DC-name>")
    takes_options = [
        Option("--backup-file", help="Path to backup file", type=str),
        Option("--targetdir", help="Path to write to", type=str),
        Option("--newservername", help="Name for new server", type=str),
        Option("--host-ip",
               type="string",
               metavar="IPADDRESS",
               help="set IPv4 ipaddress"),
        Option("--host-ip6",
               type="string",
               metavar="IP6ADDRESS",
               help="set IPv6 ipaddress"),
        Option("--site", help="Site to add the new server in", type=str),
    ]

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
    }

    def register_dns_zone(self, logger, samdb, lp, ntdsguid, host_ip, host_ip6,
                          site):
        '''
        Registers the new realm's DNS objects when a renamed domain backup
        is restored.
        '''
        names = guess_names(lp)
        domaindn = names.domaindn
        forestdn = samdb.get_root_basedn().get_linearized()
        dnsdomain = names.dnsdomain.lower()
        dnsforest = dnsdomain
        hostname = names.netbiosname.lower()
        domainsid = dom_sid(samdb.get_domain_sid())
        dnsadmins_sid = get_dnsadmins_sid(samdb, domaindn)
        domainguid = get_domainguid(samdb, domaindn)

        # work out the IP address to use for the new DC's DNS records
        host_ip = determine_host_ip(logger, lp, host_ip)
        host_ip6 = determine_host_ip6(logger, lp, host_ip6)

        if host_ip is None and host_ip6 is None:
            raise CommandError('Please specify a host-ip for the new server')

        logger.info("DNS realm was renamed to %s" % dnsdomain)
        logger.info("Populating DNS partitions for new realm...")

        # Add the DNS objects for the new realm (note: the backup clone already
        # has the root server objects, so don't add them again)
        fill_dns_data_partitions(samdb,
                                 domainsid,
                                 site,
                                 domaindn,
                                 forestdn,
                                 dnsdomain,
                                 dnsforest,
                                 hostname,
                                 host_ip,
                                 host_ip6,
                                 domainguid,
                                 ntdsguid,
                                 dnsadmins_sid,
                                 add_root=False)

    def fix_old_dc_references(self, samdb):
        '''Fixes attributes that reference the old/removed DCs'''

        # we just want to fix up DB problems here that were introduced by us
        # removing the old DCs. We restrict what we fix up so that the restored
        # DB matches the backed-up DB as close as possible. (There may be other
        # DB issues inherited from the backed-up DC, but it's not our place to
        # silently try to fix them here).
        samdb.transaction_start()
        chk = dbcheck(samdb,
                      quiet=True,
                      fix=True,
                      yes=False,
                      in_transaction=True)

        # fix up stale references to the old DC
        setattr(chk, 'fix_all_old_dn_string_component_mismatch', 'ALL')
        attrs = ['lastKnownParent', 'interSiteTopologyGenerator']

        # fix-up stale one-way links that point to the old DC
        setattr(chk, 'remove_plausible_deleted_DN_links', 'ALL')
        attrs += ['msDS-NC-Replica-Locations']

        cross_ncs_ctrl = 'search_options:1:2'
        controls = ['show_deleted:1', cross_ncs_ctrl]
        chk.check_database(controls=controls, attrs=attrs)
        samdb.transaction_commit()

    def create_default_site(self, samdb, logger):
        '''Creates the default site, if it doesn't already exist'''

        sitename = DEFAULTSITE
        search_expr = "(&(cn={0})(objectclass=site))".format(sitename)
        res = samdb.search(samdb.get_config_basedn(),
                           scope=ldb.SCOPE_SUBTREE,
                           expression=search_expr)

        if len(res) == 0:
            logger.info("Creating default site '{0}'".format(sitename))
            sites.create_site(samdb, samdb.get_config_basedn(), sitename)

        return sitename

    def run(self,
            sambaopts=None,
            credopts=None,
            backup_file=None,
            targetdir=None,
            newservername=None,
            host_ip=None,
            host_ip6=None,
            site=None):
        if not (backup_file and os.path.exists(backup_file)):
            raise CommandError('Backup file not found.')
        if targetdir is None:
            raise CommandError('Please specify a target directory')
        # allow restoredc to install into a directory prepopulated by selftest
        if (os.path.exists(targetdir) and os.listdir(targetdir)
                and os.environ.get('SAMBA_SELFTEST') != '1'):
            raise CommandError('Target directory is not empty')
        if not newservername:
            raise CommandError('Server name required')

        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG)
        logger.addHandler(logging.StreamHandler(sys.stdout))

        # ldapcmp prefers the server's netBIOS name in upper-case
        newservername = newservername.upper()

        # extract the backup .tar to a temp directory
        targetdir = os.path.abspath(targetdir)
        tf = tarfile.open(backup_file)
        tf.extractall(targetdir)
        tf.close()

        # use the smb.conf that got backed up, by default (save what was
        # actually backed up, before we mess with it)
        smbconf = os.path.join(targetdir, 'etc', 'smb.conf')
        shutil.copyfile(smbconf, smbconf + ".orig")

        # if a smb.conf was specified on the cmd line, then use that instead
        cli_smbconf = sambaopts.get_loadparm_path()
        if cli_smbconf:
            logger.info("Using %s as restored domain's smb.conf" % cli_smbconf)
            shutil.copyfile(cli_smbconf, smbconf)

        lp = samba.param.LoadParm()
        lp.load(smbconf)

        # open a DB connection to the restored DB
        private_dir = os.path.join(targetdir, 'private')
        samdb_path = os.path.join(private_dir, 'sam.ldb')
        samdb = SamDB(url=samdb_path, session_info=system_session(), lp=lp)

        if site is None:
            # There's no great way to work out the correct site to add the
            # restored DC to. By default, add it to Default-First-Site-Name,
            # creating the site if it doesn't already exist
            site = self.create_default_site(samdb, logger)
            logger.info("Adding new DC to site '{0}'".format(site))

        # Create account using the join_add_objects function in the join object
        # We need namingContexts, account control flags, and the sid saved by
        # the backup process.
        res = samdb.search(base="",
                           scope=ldb.SCOPE_BASE,
                           attrs=['namingContexts'])
        ncs = [str(r) for r in res[0].get('namingContexts')]

        creds = credopts.get_credentials(lp)
        ctx = DCJoinContext(logger,
                            creds=creds,
                            lp=lp,
                            site=site,
                            forced_local_samdb=samdb,
                            netbios_name=newservername)
        ctx.nc_list = ncs
        ctx.full_nc_list = ncs
        ctx.userAccountControl = (samba.dsdb.UF_SERVER_TRUST_ACCOUNT
                                  | samba.dsdb.UF_TRUSTED_FOR_DELEGATION)

        # rewrite the smb.conf to make sure it uses the new targetdir settings.
        # (This doesn't update all filepaths in a customized config, but it
        # corrects the same paths that get set by a new provision)
        logger.info('Updating basic smb.conf settings...')
        make_smbconf(smbconf,
                     newservername,
                     ctx.domain_name,
                     ctx.realm,
                     targetdir,
                     lp=lp,
                     serverrole="active directory domain controller")

        # Get the SID saved by the backup process and create account
        res = samdb.search(base=ldb.Dn(samdb, "@SAMBA_DSDB"),
                           scope=ldb.SCOPE_BASE,
                           attrs=['sidForRestore', 'backupRename'])
        is_rename = True if 'backupRename' in res[0] else False
        sid = res[0].get('sidForRestore')[0]
        logger.info('Creating account with SID: ' + str(sid))
        ctx.join_add_objects(specified_sid=dom_sid(sid))

        m = ldb.Message()
        m.dn = ldb.Dn(samdb, '@ROOTDSE')
        ntds_guid = str(ctx.ntds_guid)
        m["dsServiceName"] = ldb.MessageElement("<GUID=%s>" % ntds_guid,
                                                ldb.FLAG_MOD_REPLACE,
                                                "dsServiceName")
        samdb.modify(m)

        # if we renamed the backed-up domain, then we need to add the DNS
        # objects for the new realm (we do this in the restore, now that we
        # know the new DC's IP address)
        if is_rename:
            self.register_dns_zone(logger, samdb, lp, ctx.ntds_guid, host_ip,
                                   host_ip6, site)

        secrets_path = os.path.join(private_dir, 'secrets.ldb')
        secrets_ldb = Ldb(secrets_path, session_info=system_session(), lp=lp)
        secretsdb_self_join(secrets_ldb,
                            domain=ctx.domain_name,
                            realm=ctx.realm,
                            dnsdomain=ctx.dnsdomain,
                            netbiosname=ctx.myname,
                            domainsid=ctx.domsid,
                            machinepass=ctx.acct_pass,
                            key_version_number=ctx.key_version_number,
                            secure_channel_type=misc.SEC_CHAN_BDC)

        # Seize DNS roles
        domain_dn = samdb.domain_dn()
        forest_dn = samba.dn_from_dns_name(samdb.forest_dns_name())
        domaindns_dn = ("CN=Infrastructure,DC=DomainDnsZones,", domain_dn)
        forestdns_dn = ("CN=Infrastructure,DC=ForestDnsZones,", forest_dn)
        for dn_prefix, dns_dn in [forestdns_dn, domaindns_dn]:
            if dns_dn not in ncs:
                continue
            full_dn = dn_prefix + dns_dn
            m = ldb.Message()
            m.dn = ldb.Dn(samdb, full_dn)
            m["fSMORoleOwner"] = ldb.MessageElement(samdb.get_dsServiceName(),
                                                    ldb.FLAG_MOD_REPLACE,
                                                    "fSMORoleOwner")
            samdb.modify(m)

        # Seize other roles
        for role in ['rid', 'pdc', 'naming', 'infrastructure', 'schema']:
            self.seize_role(role, samdb, force=True)

        # Get all DCs and remove them (this ensures these DCs cannot
        # replicate because they will not have a password)
        search_expr = "(&(objectClass=Server)(serverReference=*))"
        res = samdb.search(samdb.get_config_basedn(),
                           scope=ldb.SCOPE_SUBTREE,
                           expression=search_expr)
        for m in res:
            cn = m.get('cn')[0]
            if cn != newservername:
                remove_dc(samdb, logger, cn)

        # Remove the repsFrom and repsTo from each NC to ensure we do
        # not try (and fail) to talk to the old DCs
        for nc in ncs:
            msg = ldb.Message()
            msg.dn = ldb.Dn(samdb, nc)

            msg["repsFrom"] = ldb.MessageElement([], ldb.FLAG_MOD_REPLACE,
                                                 "repsFrom")
            msg["repsTo"] = ldb.MessageElement([], ldb.FLAG_MOD_REPLACE,
                                               "repsTo")
            samdb.modify(msg)

        # Update the krbtgt passwords twice, ensuring no tickets from
        # the old domain are valid
        update_krbtgt_account_password(samdb)
        update_krbtgt_account_password(samdb)

        # restore the sysvol directory from the backup tar file, including the
        # original NTACLs. Note that the backup_restore() will fail if not root
        sysvol_tar = os.path.join(targetdir, 'sysvol.tar.gz')
        dest_sysvol_dir = lp.get('path', 'sysvol')
        if not os.path.exists(dest_sysvol_dir):
            os.makedirs(dest_sysvol_dir)
        backup_restore(sysvol_tar, dest_sysvol_dir, samdb, smbconf)
        os.remove(sysvol_tar)

        # fix up any stale links to the old DCs we just removed
        logger.info("Fixing up any remaining references to the old DCs...")
        self.fix_old_dc_references(samdb)

        # Remove DB markers added by the backup process
        m = ldb.Message()
        m.dn = ldb.Dn(samdb, "@SAMBA_DSDB")
        m["backupDate"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE,
                                             "backupDate")
        m["sidForRestore"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE,
                                                "sidForRestore")
        if is_rename:
            m["backupRename"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE,
                                                   "backupRename")
        samdb.modify(m)

        logger.info("Backup file successfully restored to %s" % targetdir)
        logger.info("Please check the smb.conf settings are correct before "
                    "starting samba.")
Exemplo n.º 11
0
class cmd_domain_backup_rename(samba.netcmd.Command):
    '''Copy a running DC's DB to backup file, renaming the domain in the process.

    Where <new-domain> is the new domain's NetBIOS name, and <new-dnsrealm> is
    the new domain's realm in DNS form.

    This is similar to 'samba-tool backup online' in that it clones the DB of a
    running DC. However, this option also renames all the domain entries in the
    DB. Renaming the domain makes it possible to restore and start a new Samba
    DC without it interfering with the existing Samba domain. In other words,
    you could use this option to clone your production samba domain and restore
    it to a separate pre-production environment that won't overlap or interfere
    with the existing production Samba domain.

    Note that:
    - it's recommended to run 'samba-tool dbcheck' before taking a backup-file
      and fix any errors it reports.
    - all the domain's secrets are included in the backup file.
    - although the DB contents can be untarred and examined manually, you need
      to run 'samba-tool domain backup restore' before you can start a Samba DC
      from the backup file.
    - GPO and sysvol information will still refer to the old realm and will
      need to be updated manually.
    - if you specify 'keep-dns-realm', then the DNS records will need updating
      in order to work (they will still refer to the old DC's IP instead of the
      new DC's address).
    - we recommend that you only use this option if you know what you're doing.
    '''

    synopsis = ("%prog <new-domain> <new-dnsrealm> --server=<DC-to-backup> "
                "--targetdir=<output-dir>")
    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option("--server", help="The DC to backup", type=str),
        Option("--targetdir",
               help="Directory to write the backup file",
               type=str),
        Option("--keep-dns-realm",
               action="store_true",
               default=False,
               help="Retain the DNS entries for the old realm in the backup"),
        Option("--no-secrets",
               action="store_true",
               default=False,
               help="Exclude secret values from the backup created")
    ]

    takes_args = ["new_domain_name", "new_dns_realm"]

    def update_dns_root(self, logger, samdb, old_realm, delete_old_dns):
        '''Updates dnsRoot for the partition objects to reflect the rename'''

        # lookup the crossRef objects that hold the old realm's dnsRoot
        partitions_dn = samdb.get_partitions_dn()
        res = samdb.search(base=partitions_dn,
                           scope=ldb.SCOPE_ONELEVEL,
                           attrs=["dnsRoot"],
                           expression='(&(objectClass=crossRef)(dnsRoot=*))')
        new_realm = samdb.domain_dns_name()

        # go through and add the new realm
        for res_msg in res:
            # dnsRoot can be multi-valued, so only look for the old realm
            for dns_root in res_msg["dnsRoot"]:
                dn = res_msg.dn
                if old_realm in dns_root:
                    new_dns_root = re.sub('%s$' % old_realm, new_realm,
                                          dns_root)
                    logger.info("Adding %s dnsRoot to %s" % (new_dns_root, dn))

                    m = ldb.Message()
                    m.dn = dn
                    m["dnsRoot"] = ldb.MessageElement(new_dns_root,
                                                      ldb.FLAG_MOD_ADD,
                                                      "dnsRoot")
                    samdb.modify(m)

                    # optionally remove the dnsRoot for the old realm
                    if delete_old_dns:
                        logger.info("Removing %s dnsRoot from %s" %
                                    (dns_root, dn))
                        m["dnsRoot"] = ldb.MessageElement(
                            dns_root, ldb.FLAG_MOD_DELETE, "dnsRoot")
                        samdb.modify(m)

    # Updates the CN=<domain>,CN=Partitions,CN=Configuration,... object to
    # reflect the domain rename
    def rename_domain_partition(self, logger, samdb, new_netbios_name):
        '''Renames the domain parition object and updates its nETBIOSName'''

        # lookup the crossRef object that holds the nETBIOSName (nCName has
        # already been updated by this point, but the netBIOS hasn't)
        base_dn = samdb.get_default_basedn()
        nc_name = ldb.binary_encode(str(base_dn))
        partitions_dn = samdb.get_partitions_dn()
        res = samdb.search(base=partitions_dn,
                           scope=ldb.SCOPE_ONELEVEL,
                           attrs=["nETBIOSName"],
                           expression='ncName=%s' % nc_name)

        logger.info("Changing backup domain's NetBIOS name to %s" %
                    new_netbios_name)
        m = ldb.Message()
        m.dn = res[0].dn
        m["nETBIOSName"] = ldb.MessageElement(new_netbios_name,
                                              ldb.FLAG_MOD_REPLACE,
                                              "nETBIOSName")
        samdb.modify(m)

        # renames the object itself to reflect the change in domain
        new_dn = "CN=%s,%s" % (new_netbios_name, partitions_dn)
        logger.info("Renaming %s --> %s" % (res[0].dn, new_dn))
        samdb.rename(res[0].dn, new_dn, controls=['relax:0'])

    def delete_old_dns_zones(self, logger, samdb, old_realm):
        # remove the top-level DNS entries for the old realm
        basedn = samdb.get_default_basedn()
        dn = "DC=%s,CN=MicrosoftDNS,DC=DomainDnsZones,%s" % (old_realm, basedn)
        logger.info("Deleting old DNS zone %s" % dn)
        samdb.delete(dn, ["tree_delete:1"])

        forestdn = samdb.get_root_basedn().get_linearized()
        dn = "DC=_msdcs.%s,CN=MicrosoftDNS,DC=ForestDnsZones,%s" % (old_realm,
                                                                    forestdn)
        logger.info("Deleting old DNS zone %s" % dn)
        samdb.delete(dn, ["tree_delete:1"])

    def fix_old_dn_attributes(self, samdb):
        '''Fixes attributes (i.e. objectCategory) that still use the old DN'''

        samdb.transaction_start()
        # Just fix any mismatches in DN detected (leave any other errors)
        chk = dbcheck(samdb,
                      quiet=True,
                      fix=True,
                      yes=False,
                      in_transaction=True)
        # fix up incorrect objectCategory/etc attributes
        setattr(chk, 'fix_all_old_dn_string_component_mismatch', 'ALL')
        cross_ncs_ctrl = 'search_options:1:2'
        controls = ['show_deleted:1', cross_ncs_ctrl]
        chk.check_database(controls=controls)
        samdb.transaction_commit()

    def run(self,
            new_domain_name,
            new_dns_realm,
            sambaopts=None,
            credopts=None,
            server=None,
            targetdir=None,
            keep_dns_realm=False,
            no_secrets=False):
        logger = self.get_logger()
        logger.setLevel(logging.INFO)

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp)

        # Make sure we have all the required args.
        if server is None:
            raise CommandError('Server required')

        check_targetdir(logger, targetdir)

        delete_old_dns = not keep_dns_realm

        new_dns_realm = new_dns_realm.lower()
        new_domain_name = new_domain_name.upper()

        new_base_dn = samba.dn_from_dns_name(new_dns_realm)
        logger.info("New realm for backed up domain: %s" % new_dns_realm)
        logger.info("New base DN for backed up domain: %s" % new_base_dn)
        logger.info("New domain NetBIOS name: %s" % new_domain_name)

        tmpdir = tempfile.mkdtemp(dir=targetdir)

        # setup a join-context for cloning the remote server
        include_secrets = not no_secrets
        ctx = DCCloneAndRenameContext(new_base_dn,
                                      new_domain_name,
                                      new_dns_realm,
                                      logger=logger,
                                      creds=creds,
                                      lp=lp,
                                      include_secrets=include_secrets,
                                      dns_backend='SAMBA_INTERNAL',
                                      server=server,
                                      targetdir=tmpdir)

        # sanity-check we're not "renaming" the domain to the same values
        old_domain = ctx.domain_name
        if old_domain == new_domain_name:
            shutil.rmtree(tmpdir)
            raise CommandError("Cannot use the current domain NetBIOS name.")

        old_realm = ctx.realm
        if old_realm == new_dns_realm:
            shutil.rmtree(tmpdir)
            raise CommandError("Cannot use the current domain DNS realm.")

        # do the clone/rename
        ctx.do_join()

        # get the paths used for the clone, then drop the old samdb connection
        del ctx.local_samdb
        paths = ctx.paths

        # get a free RID to use as the new DC's SID (when it gets restored)
        remote_sam = SamDB(url='ldap://' + server,
                           credentials=creds,
                           session_info=system_session(),
                           lp=lp)
        new_sid = get_sid_for_restore(remote_sam)

        # Grab the remote DC's sysvol files and bundle them into a tar file.
        # Note we end up with 2 sysvol dirs - the original domain's files (that
        # use the old realm) backed here, as well as default files generated
        # for the new realm as part of the clone/join.
        sysvol_tar = os.path.join(tmpdir, 'sysvol.tar.gz')
        smb_conn = smb.SMB(server, "sysvol", lp=lp, creds=creds, sign=True)
        backup_online(smb_conn, sysvol_tar, remote_sam.get_domain_sid())

        # connect to the local DB (making sure we use the new/renamed config)
        lp.load(paths.smbconf)
        samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp)

        # Edit the cloned sam.ldb to mark it as a backup
        time_str = get_timestamp()
        add_backup_marker(samdb, "backupDate", time_str)
        add_backup_marker(samdb, "sidForRestore", new_sid)
        add_backup_marker(samdb, "backupRename", old_realm)

        # fix up the DNS objects that are using the old dnsRoot value
        self.update_dns_root(logger, samdb, old_realm, delete_old_dns)

        # update the netBIOS name and the Partition object for the domain
        self.rename_domain_partition(logger, samdb, new_domain_name)

        if delete_old_dns:
            self.delete_old_dns_zones(logger, samdb, old_realm)

        logger.info("Fixing DN attributes after rename...")
        self.fix_old_dn_attributes(samdb)

        # ensure the admin user always has a password set (same as provision)
        if no_secrets:
            set_admin_password(logger, samdb)

        # Add everything in the tmpdir to the backup tar file
        backup_file = backup_filepath(targetdir, new_dns_realm, time_str)
        create_log_file(
            tmpdir, lp, "rename", server, include_secrets,
            "Original domain %s (NetBIOS), %s (DNS realm)" %
            (old_domain, old_realm))
        create_backup_tar(logger, tmpdir, backup_file)

        shutil.rmtree(tmpdir)
Exemplo n.º 12
0
class cmd_domain_backup_online(samba.netcmd.Command):
    '''Copy a running DC's current DB into a backup tar file.

    Takes a backup copy of the current domain from a running DC. If the domain
    were to undergo a catastrophic failure, then the backup file can be used to
    recover the domain. The backup created is similar to the DB that a new DC
    would receive when it joins the domain.

    Note that:
    - it's recommended to run 'samba-tool dbcheck' before taking a backup-file
      and fix any errors it reports.
    - all the domain's secrets are included in the backup file.
    - although the DB contents can be untarred and examined manually, you need
      to run 'samba-tool domain backup restore' before you can start a Samba DC
      from the backup file.'''

    synopsis = "%prog --server=<DC-to-backup> --targetdir=<output-dir>"
    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option("--server", help="The DC to backup", type=str),
        Option("--targetdir",
               type=str,
               help="Directory to write the backup file to"),
        Option("--no-secrets",
               action="store_true",
               default=False,
               help="Exclude secret values from the backup created")
    ]

    def run(self,
            sambaopts=None,
            credopts=None,
            server=None,
            targetdir=None,
            no_secrets=False):
        logger = self.get_logger()
        logger.setLevel(logging.DEBUG)

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp)

        # Make sure we have all the required args.
        if server is None:
            raise CommandError('Server required')

        check_targetdir(logger, targetdir)

        tmpdir = tempfile.mkdtemp(dir=targetdir)

        # Run a clone join on the remote
        include_secrets = not no_secrets
        ctx = join_clone(logger=logger,
                         creds=creds,
                         lp=lp,
                         include_secrets=include_secrets,
                         server=server,
                         dns_backend='SAMBA_INTERNAL',
                         targetdir=tmpdir)

        # get the paths used for the clone, then drop the old samdb connection
        paths = ctx.paths
        del ctx

        # Get a free RID to use as the new DC's SID (when it gets restored)
        remote_sam = SamDB(url='ldap://' + server,
                           credentials=creds,
                           session_info=system_session(),
                           lp=lp)
        new_sid = get_sid_for_restore(remote_sam)
        realm = remote_sam.domain_dns_name()

        # Grab the remote DC's sysvol files and bundle them into a tar file
        sysvol_tar = os.path.join(tmpdir, 'sysvol.tar.gz')
        smb_conn = smb.SMB(server, "sysvol", lp=lp, creds=creds, sign=True)
        backup_online(smb_conn, sysvol_tar, remote_sam.get_domain_sid())

        # remove the default sysvol files created by the clone (we want to
        # make sure we restore the sysvol.tar.gz files instead)
        shutil.rmtree(paths.sysvol)

        # Edit the downloaded sam.ldb to mark it as a backup
        samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp)
        time_str = get_timestamp()
        add_backup_marker(samdb, "backupDate", time_str)
        add_backup_marker(samdb, "sidForRestore", new_sid)

        # ensure the admin user always has a password set (same as provision)
        if no_secrets:
            set_admin_password(logger, samdb)

        # Add everything in the tmpdir to the backup tar file
        backup_file = backup_filepath(targetdir, realm, time_str)
        create_log_file(tmpdir, lp, "online", server, include_secrets)
        create_backup_tar(logger, tmpdir, backup_file)

        shutil.rmtree(tmpdir)
Exemplo n.º 13
0
class cmd_ds_acl_set(Command):
    """Modify access list on a directory object"""

    synopsis = "set --objectdn=objectdn --car=control right --action=[deny|allow] --trusteedn=trustee-dn"
    car_help = """ The access control right to allow or deny """

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
        "versionopts": options.VersionOptions,
    }

    takes_options = [
        Option("--host",
               help="LDB URL for database or target server",
               type=str),
        Option("--car",
               type="choice",
               choices=[
                   "change-rid", "change-pdc", "change-infrastructure",
                   "change-schema", "change-naming", "allocate_rids",
                   "get-changes", "get-changes-all", "get-changes-filtered",
                   "topology-manage", "topology-monitor", "repl-sync",
                   "ro-repl-secret-sync"
               ],
               help=car_help),
        Option("--action",
               type="choice",
               choices=["allow", "deny"],
               help="""Deny or allow access"""),
        Option("--objectdn",
               help="DN of the object whose SD to modify",
               type="string"),
        Option("--trusteedn",
               help="DN of the entity that gets access",
               type="string"),
        Option("--sddl",
               help="An ACE or group of ACEs to be added on the object",
               type="string"),
    ]

    def find_trustee_sid(self, samdb, trusteedn):
        res = samdb.search(base=trusteedn,
                           expression="(objectClass=*)",
                           scope=SCOPE_BASE)
        assert (len(res) == 1)
        return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])

    def modify_descriptor(self, samdb, object_dn, desc, controls=None):
        assert (isinstance(desc, security.descriptor))
        m = ldb.Message()
        m.dn = ldb.Dn(samdb, object_dn)
        m["nTSecurityDescriptor"] = ldb.MessageElement(
            (ndr_pack(desc)), ldb.FLAG_MOD_REPLACE, "nTSecurityDescriptor")
        samdb.modify(m)

    def read_descriptor(self, samdb, object_dn):
        res = samdb.search(base=object_dn,
                           scope=SCOPE_BASE,
                           attrs=["nTSecurityDescriptor"])
        # we should theoretically always have an SD
        assert (len(res) == 1)
        desc = res[0]["nTSecurityDescriptor"][0]
        return ndr_unpack(security.descriptor, desc)

    def get_domain_sid(self, samdb):
        res = samdb.search(base=samdb.domain_dn(),
                           expression="(objectClass=*)",
                           scope=SCOPE_BASE)
        return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])

    def add_ace(self, samdb, object_dn, new_ace):
        """Add new ace explicitly."""
        desc = self.read_descriptor(samdb, object_dn)
        desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
        #TODO add bindings for descriptor manipulation and get rid of this
        desc_aces = re.findall("\(.*?\)", desc_sddl)
        for ace in desc_aces:
            if ("ID" in ace):
                desc_sddl = desc_sddl.replace(ace, "")
        if new_ace in desc_sddl:
            return
        if desc_sddl.find("(") >= 0:
            desc_sddl = desc_sddl[:desc_sddl.index("(")] + new_ace + desc_sddl[
                desc_sddl.index("("):]
        else:
            desc_sddl = desc_sddl + new_ace
        desc = security.descriptor.from_sddl(desc_sddl,
                                             self.get_domain_sid(samdb))
        self.modify_descriptor(samdb, object_dn, desc)

    def print_new_acl(self, samdb, object_dn):
        desc = self.read_descriptor(samdb, object_dn)
        desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
        print "new descriptor for %s:" % object_dn
        print desc_sddl

    def run(self,
            car,
            action,
            objectdn,
            trusteedn,
            sddl,
            host=None,
            credopts=None,
            sambaopts=None,
            versionopts=None):
        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp)

        if sddl is None and (car is None or action is None or objectdn is None
                             or trusteedn is None):
            return self.usage()

        samdb = SamDB(url=host,
                      session_info=system_session(),
                      credentials=creds,
                      lp=lp)
        cars = {
            'change-rid': GUID_DRS_CHANGE_RID_MASTER,
            'change-pdc': GUID_DRS_CHANGE_PDC,
            'change-infrastructure': GUID_DRS_CHANGE_INFR_MASTER,
            'change-schema': GUID_DRS_CHANGE_SCHEMA_MASTER,
            'change-naming': GUID_DRS_CHANGE_DOMAIN_MASTER,
            'allocate_rids': GUID_DRS_ALLOCATE_RIDS,
            'get-changes': GUID_DRS_GET_CHANGES,
            'get-changes-all': GUID_DRS_GET_ALL_CHANGES,
            'get-changes-filtered': GUID_DRS_GET_FILTERED_ATTRIBUTES,
            'topology-manage': GUID_DRS_MANAGE_TOPOLOGY,
            'topology-monitor': GUID_DRS_MONITOR_TOPOLOGY,
            'repl-sync': GUID_DRS_REPL_SYNCRONIZE,
            'ro-repl-secret-sync': GUID_DRS_RO_REPL_SECRET_SYNC,
        }
        sid = self.find_trustee_sid(samdb, trusteedn)
        if sddl:
            new_ace = sddl
        elif action == "allow":
            new_ace = "(OA;;CR;%s;;%s)" % (cars[car], str(sid))
        elif action == "deny":
            new_ace = "(OD;;CR;%s;;%s)" % (cars[car], str(sid))
        else:
            raise CommandError("Wrong argument '%s'!" % action)

        self.print_new_acl(samdb, objectdn)
        self.add_ace(samdb, objectdn, new_ace)
        self.print_new_acl(samdb, objectdn)
Exemplo n.º 14
0
class cmd_testparm(Command):
    """Syntax check the configuration file."""

    synopsis = "%prog [options]"

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions
    }

    takes_options = [
        Option("--section-name",
               type=str,
               help="Limit testparm to a named section"),
        Option("--parameter-name",
               type=str,
               help="Limit testparm to a named parameter"),
        Option("--client-name",
               type=str,
               help="Client DNS name for 'hosts allow' checking "
               "(should match reverse lookup)"),
        Option("--client-ip",
               type=str,
               help="Client IP address for 'hosts allow' checking"),
        Option("--suppress-prompt",
               action="store_true",
               default=False,
               help="Suppress prompt for enter"),
        Option("-v",
               "--verbose",
               action="store_true",
               default=False,
               help="Show default options too"),
        # We need support for smb.conf macros before this will work again
        Option("--server", type=str, help="Set %L macro to servername"),
        # These are harder to do with the new code structure
        Option("--show-all-parameters",
               action="store_true",
               default=False,
               help="Show the parameters, type, possible values")
    ]

    takes_args = []

    def run(self,
            sambaopts,
            versionopts,
            section_name=None,
            parameter_name=None,
            client_ip=None,
            client_name=None,
            verbose=False,
            suppress_prompt=None,
            show_all_parameters=False,
            server=None):
        if server:
            raise NotImplementedError("--server not yet implemented")
        if show_all_parameters:
            raise NotImplementedError(
                "--show-all-parameters not yet implemented")
        if client_name is not None and client_ip is None:
            raise CommandError("Both a DNS name and an IP address are "
                               "required for the host access check")

        try:
            lp = sambaopts.get_loadparm()
        except RuntimeError, err:
            raise CommandError(err)

        # We need this to force the output
        samba.set_debug_level(2)

        logger = self.get_logger("testparm")

        logger.info("Loaded smb config files from %s", lp.configfile)
        logger.info("Loaded services file OK.")

        valid = self.do_global_checks(lp, logger)
        valid = valid and self.do_share_checks(lp, logger)
        if client_name is not None and client_ip is not None:
            self.check_client_access(lp, logger, client_name, client_ip)
        else:
            if section_name is not None or parameter_name is not None:
                if parameter_name is None:
                    lp[section_name].dump(sys.stdout, lp.default_service,
                                          verbose)
                else:
                    lp.dump_a_parameter(sys.stdout, parameter_name,
                                        section_name)
            else:
                if not suppress_prompt:
                    self.outf.write(
                        "Press enter to see a dump of your service definitions\n"
                    )
                    sys.stdin.readline()
                lp.dump(sys.stdout, verbose)
        if valid:
            return
        else:
            raise CommandError("Invalid smb.conf")
Exemplo n.º 15
0
class cmd_drs_showrepl(Command):
    """Show replication status."""

    synopsis = "%prog [<DC>] [options]"

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option("--json",
               help="replication details in JSON format",
               dest='format',
               action='store_const',
               const='json'),
        Option("--summary",
               help=("summarize overall DRS health as seen "
                     "from this server"),
               dest='format',
               action='store_const',
               const='summary'),
        Option("--pull-summary",
               help=("Have we successfully replicated "
                     "from all relevent servers?"),
               dest='format',
               action='store_const',
               const='pull_summary'),
        Option("--notify-summary",
               action='store_const',
               const='notify_summary',
               dest='format',
               help=("Have we successfully notified all relevent servers of "
                     "local changes, and did they say they successfully "
                     "replicated?")),
        Option("--classic",
               help="print local replication details",
               dest='format',
               action='store_const',
               const='classic',
               default=DEFAULT_SHOWREPL_FORMAT),
        Option("-v", "--verbose", help="Be verbose", action="store_true"),
        Option("--color", help="Use colour output (yes|no|auto)",
               default='no'),
    ]

    takes_args = ["DC?"]

    def parse_neighbour(self, n):
        """Convert an ldb neighbour object into a python dictionary"""
        dsa_objectguid = str(n.source_dsa_obj_guid)
        d = {
            'NC dn': n.naming_context_dn,
            "DSA objectGUID": dsa_objectguid,
            "last attempt time": nttime2string(n.last_attempt),
            "last attempt message": drs_errmsg(n.result_last_attempt),
            "consecutive failures": n.consecutive_sync_failures,
            "last success": nttime2string(n.last_success),
            "NTDS DN": str(n.source_dsa_obj_dn),
            'is deleted': False
        }

        try:
            self.samdb.search(base="<GUID=%s>" % dsa_objectguid,
                              scope=ldb.SCOPE_BASE,
                              attrs=[])
        except ldb.LdbError as e:
            (errno, _) = e.args
            if errno == ldb.ERR_NO_SUCH_OBJECT:
                d['is deleted'] = True
            else:
                raise
        try:
            (site, server) = drs_parse_ntds_dn(n.source_dsa_obj_dn)
            d["DSA"] = "%s\%s" % (site, server)
        except RuntimeError:
            pass
        return d

    def print_neighbour(self, d):
        '''print one set of neighbour information'''
        self.message("%s" % d['NC dn'])
        if 'DSA' in d:
            self.message("\t%s via RPC" % d['DSA'])
        else:
            self.message("\tNTDS DN: %s" % d['NTDS DN'])
        self.message("\t\tDSA object GUID: %s" % d['DSA objectGUID'])
        self.message("\t\tLast attempt @ %s %s" %
                     (d['last attempt time'], d['last attempt message']))
        self.message("\t\t%u consecutive failure(s)." %
                     d['consecutive failures'])
        self.message("\t\tLast success @ %s" % d['last success'])
        self.message("")

    def get_neighbours(self, info_type):
        req1 = drsuapi.DsReplicaGetInfoRequest1()
        req1.info_type = info_type
        try:
            (info_type,
             info) = self.drsuapi.DsReplicaGetInfo(self.drsuapi_handle, 1,
                                                   req1)
        except Exception as e:
            raise CommandError(
                "DsReplicaGetInfo of type %u failed" % info_type, e)

        reps = [self.parse_neighbour(n) for n in info.array]
        return reps

    def run(self,
            DC=None,
            sambaopts=None,
            credopts=None,
            versionopts=None,
            format=DEFAULT_SHOWREPL_FORMAT,
            verbose=False,
            color='no'):
        self.apply_colour_choice(color)
        self.lp = sambaopts.get_loadparm()
        if DC is None:
            DC = common.netcmd_dnsname(self.lp)
        self.server = DC
        self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
        self.verbose = verbose

        output_function = {
            'summary': self.summary_output,
            'notify_summary': self.notify_summary_output,
            'pull_summary': self.pull_summary_output,
            'json': self.json_output,
            'classic': self.classic_output,
        }.get(format)
        if output_function is None:
            raise CommandError("unknown showrepl format %s" % format)

        return output_function()

    def json_output(self):
        data = self.get_local_repl_data()
        del data['site']
        del data['server']
        json.dump(data, self.outf, indent=2)

    def summary_output_handler(self, typeof_output):
        """Print a short message if every seems fine, but print details of any
        links that seem broken."""
        failing_repsto = []
        failing_repsfrom = []

        local_data = self.get_local_repl_data()

        if typeof_output != "pull_summary":
            for rep in local_data['repsTo']:
                if rep['is deleted']:
                    continue
                if rep["consecutive failures"] != 0 or rep["last success"] == 0:
                    failing_repsto.append(rep)

        if typeof_output != "notify_summary":
            for rep in local_data['repsFrom']:
                if rep['is deleted']:
                    continue
                if rep["consecutive failures"] != 0 or rep["last success"] == 0:
                    failing_repsfrom.append(rep)

        if failing_repsto or failing_repsfrom:
            self.message(colour.c_RED("There are failing connections"))
            if failing_repsto:
                self.message(colour.c_RED("Failing outbound connections:"))
                for rep in failing_repsto:
                    self.print_neighbour(rep)
            if failing_repsfrom:
                self.message(colour.c_RED("Failing inbound connection:"))
                for rep in failing_repsfrom:
                    self.print_neighbour(rep)

            return 1

        self.message(colour.c_GREEN("[ALL GOOD]"))

    def summary_output(self):
        return self.summary_output_handler("summary")

    def notify_summary_output(self):
        return self.summary_output_handler("notify_summary")

    def pull_summary_output(self):
        return self.summary_output_handler("pull_summary")

    def get_local_repl_data(self):
        drsuapi_connect(self)
        samdb_connect(self)

        # show domain information
        ntds_dn = self.samdb.get_dsServiceName()

        (site, server) = drs_parse_ntds_dn(ntds_dn)
        try:
            ntds = self.samdb.search(
                base=ntds_dn,
                scope=ldb.SCOPE_BASE,
                attrs=['options', 'objectGUID', 'invocationId'])
        except Exception as e:
            raise CommandError("Failed to search NTDS DN %s" % ntds_dn)

        dsa_details = {
            "options":
            int(attr_default(ntds[0], "options", 0)),
            "objectGUID":
            get_string(
                self.samdb.schema_format_value("objectGUID",
                                               ntds[0]["objectGUID"][0])),
            "invocationId":
            get_string(
                self.samdb.schema_format_value("objectGUID",
                                               ntds[0]["invocationId"][0]))
        }

        conn = self.samdb.search(base=ntds_dn,
                                 expression="(objectClass=nTDSConnection)")
        repsfrom = self.get_neighbours(
            drsuapi.DRSUAPI_DS_REPLICA_INFO_NEIGHBORS)
        repsto = self.get_neighbours(drsuapi.DRSUAPI_DS_REPLICA_INFO_REPSTO)

        conn_details = []
        for c in conn:
            c_rdn, sep, c_server_dn = str(c['fromServer'][0]).partition(',')
            d = {
                'name':
                str(c['name']),
                'remote DN':
                str(c['fromServer'][0]),
                'options':
                int(attr_default(c, 'options', 0)),
                'enabled':
                (get_string(attr_default(c, 'enabledConnection',
                                         'TRUE')).upper() == 'TRUE')
            }

            conn_details.append(d)
            try:
                c_server_res = self.samdb.search(base=c_server_dn,
                                                 scope=ldb.SCOPE_BASE,
                                                 attrs=["dnsHostName"])
                d['dns name'] = str(c_server_res[0]["dnsHostName"][0])
            except ldb.LdbError as e:
                (errno, _) = e.args
                if errno == ldb.ERR_NO_SUCH_OBJECT:
                    d['is deleted'] = True
            except (KeyError, IndexError):
                pass

            d['replicates NC'] = []
            for r in c.get('mS-DS-ReplicatesNCReason', []):
                a = str(r).split(':')
                d['replicates NC'].append((a[3], int(a[2])))

        return {
            'dsa': dsa_details,
            'repsFrom': repsfrom,
            'repsTo': repsto,
            'NTDSConnections': conn_details,
            'site': site,
            'server': server
        }

    def classic_output(self):
        data = self.get_local_repl_data()
        dsa_details = data['dsa']
        repsfrom = data['repsFrom']
        repsto = data['repsTo']
        conn_details = data['NTDSConnections']
        site = data['site']
        server = data['server']

        self.message("%s\\%s" % (site, server))
        self.message("DSA Options: 0x%08x" % dsa_details["options"])
        self.message("DSA object GUID: %s" % dsa_details["objectGUID"])
        self.message("DSA invocationId: %s\n" % dsa_details["invocationId"])

        self.message("==== INBOUND NEIGHBORS ====\n")
        for n in repsfrom:
            self.print_neighbour(n)

        self.message("==== OUTBOUND NEIGHBORS ====\n")
        for n in repsto:
            self.print_neighbour(n)

        reasons = [
            'NTDSCONN_KCC_GC_TOPOLOGY', 'NTDSCONN_KCC_RING_TOPOLOGY',
            'NTDSCONN_KCC_MINIMIZE_HOPS_TOPOLOGY',
            'NTDSCONN_KCC_STALE_SERVERS_TOPOLOGY',
            'NTDSCONN_KCC_OSCILLATING_CONNECTION_TOPOLOGY',
            'NTDSCONN_KCC_INTERSITE_GC_TOPOLOGY',
            'NTDSCONN_KCC_INTERSITE_TOPOLOGY',
            'NTDSCONN_KCC_SERVER_FAILOVER_TOPOLOGY',
            'NTDSCONN_KCC_SITE_FAILOVER_TOPOLOGY',
            'NTDSCONN_KCC_REDUNDANT_SERVER_TOPOLOGY'
        ]

        self.message("==== KCC CONNECTION OBJECTS ====\n")
        for d in conn_details:
            self.message("Connection --")
            if d.get('is deleted'):
                self.message("\tWARNING: Connection to DELETED server!")

            self.message("\tConnection name: %s" % d['name'])
            self.message("\tEnabled        : %s" % str(d['enabled']).upper())
            self.message("\tServer DNS name : %s" % d.get('dns name'))
            self.message("\tServer DN name  : %s" % d['remote DN'])
            self.message("\t\tTransportType: RPC")
            self.message("\t\toptions: 0x%08X" % d['options'])

            if d['replicates NC']:
                for nc, reason in d['replicates NC']:
                    self.message("\t\tReplicatesNC: %s" % nc)
                    self.message("\t\tReason: 0x%08x" % reason)
                    for s in reasons:
                        if getattr(dsdb, s, 0) & reason:
                            self.message("\t\t\t%s" % s)
            else:
                self.message("Warning: No NC replicated for Connection!")
Exemplo n.º 16
0
class cmd_zonecreate(Command):
    """Create a zone."""

    synopsis = '%prog <server> <zone> [options]'

    takes_args = [ 'server', 'zone' ]

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option('--client-version', help='Client Version',
                default='longhorn', metavar='w2k|dotnet|longhorn',
                choices=['w2k','dotnet','longhorn'], dest='cli_ver')
    ]

    def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
            versionopts=None):

        self.lp = sambaopts.get_loadparm()
        self.creds = credopts.get_credentials(self.lp)
        dns_conn = dns_connect(server, self.lp, self.creds)

        zone = zone.lower()

        client_version = dns_client_version(cli_ver)
        if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
            typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_W2K
            zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_W2K()
            zone_create_info.pszZoneName = zone
            zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
            zone_create_info.fAging = 0
            zone_create_info.fDsIntegrated = 1
            zone_create_info.fLoadExisting = 1
        elif client_version == dnsserver.DNS_CLIENT_VERSION_DOTNET:
            typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_DOTNET
            zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_DOTNET()
            zone_create_info.pszZoneName = zone
            zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
            zone_create_info.fAging = 0
            zone_create_info.fDsIntegrated = 1
            zone_create_info.fLoadExisting = 1
            zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
        else:
            typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE
            zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
            zone_create_info.pszZoneName = zone
            zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
            zone_create_info.fAging = 0
            zone_create_info.fDsIntegrated = 1
            zone_create_info.fLoadExisting = 1
            zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT

        res = dns_conn.DnssrvOperation2(client_version, 0, server, None,
                                        0, 'ZoneCreate', typeid,
                                        zone_create_info)

        typeid = dnsserver.DNSSRV_TYPEID_NAME_AND_PARAM
        name_and_param = dnsserver.DNS_RPC_NAME_AND_PARAM()
        name_and_param.pszNodeName = 'AllowUpdate'
        name_and_param.dwParam = dnsp.DNS_ZONE_UPDATE_SECURE

        res = dns_conn.DnssrvOperation2(client_version, 0, server, zone,
                                        0, 'ResetDwordProperty', typeid,
                                        name_and_param)
        self.outf.write('Zone %s created successfully\n' % zone)
Exemplo n.º 17
0
class cmd_drs_replicate(Command):
    """Replicate a naming context between two DCs."""

    synopsis = "%prog <destinationDC> <sourceDC> <NC> [options]"

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_args = ["DEST_DC", "SOURCE_DC", "NC"]

    takes_options = [
        Option("--add-ref",
               help="use ADD_REF to add to repsTo on source",
               action="store_true"),
        Option("--sync-forced",
               help="use SYNC_FORCED to force inbound replication",
               action="store_true"),
        Option("--sync-all",
               help="use SYNC_ALL to replicate from all DCs",
               action="store_true"),
        Option("--full-sync", help="resync all objects", action="store_true"),
        Option(
            "--local",
            help=
            "pull changes directly into the local database (destination DC is ignored)",
            action="store_true"),
        Option(
            "--local-online",
            help=
            "pull changes into the local database (destination DC is ignored) as a normal online replication",
            action="store_true"),
        Option("--async-op",
               help="use ASYNC_OP for the replication",
               action="store_true"),
        Option(
            "--single-object",
            help=
            "Replicate only the object specified, instead of the whole Naming Context (only with --local)",
            action="store_true"),
    ]

    def drs_local_replicate(self,
                            SOURCE_DC,
                            NC,
                            full_sync=False,
                            single_object=False,
                            sync_forced=False):
        '''replicate from a source DC to the local SAM'''

        self.server = SOURCE_DC
        drsuapi_connect(self)

        self.local_samdb = SamDB(session_info=system_session(),
                                 url=None,
                                 credentials=self.creds,
                                 lp=self.lp)

        self.samdb = SamDB(url="ldap://%s" % self.server,
                           session_info=system_session(),
                           credentials=self.creds,
                           lp=self.lp)

        # work out the source and destination GUIDs
        res = self.local_samdb.search(base="",
                                      scope=ldb.SCOPE_BASE,
                                      attrs=["dsServiceName"])
        self.ntds_dn = res[0]["dsServiceName"][0]

        res = self.local_samdb.search(base=self.ntds_dn,
                                      scope=ldb.SCOPE_BASE,
                                      attrs=["objectGUID"])
        self.ntds_guid = misc.GUID(
            self.samdb.schema_format_value("objectGUID",
                                           res[0]["objectGUID"][0]))

        source_dsa_invocation_id = misc.GUID(self.samdb.get_invocation_id())
        dest_dsa_invocation_id = misc.GUID(
            self.local_samdb.get_invocation_id())
        destination_dsa_guid = self.ntds_guid

        exop = drsuapi.DRSUAPI_EXOP_NONE

        if single_object:
            exop = drsuapi.DRSUAPI_EXOP_REPL_OBJ
            full_sync = True

        self.samdb.transaction_start()
        repl = drs_utils.drs_Replicate("ncacn_ip_tcp:%s[seal]" % self.server,
                                       self.lp, self.creds, self.local_samdb,
                                       dest_dsa_invocation_id)

        # Work out if we are an RODC, so that a forced local replicate
        # with the admin pw does not sync passwords
        rodc = self.local_samdb.am_rodc()
        try:
            (num_objects, num_links) = repl.replicate(NC,
                                                      source_dsa_invocation_id,
                                                      destination_dsa_guid,
                                                      rodc=rodc,
                                                      full_sync=full_sync,
                                                      exop=exop,
                                                      sync_forced=sync_forced)
        except Exception as e:
            raise CommandError("Error replicating DN %s" % NC, e)
        self.samdb.transaction_commit()

        if full_sync:
            self.message(
                "Full Replication of all %d objects and %d links "
                "from %s to %s was successful." %
                (num_objects, num_links, SOURCE_DC, self.local_samdb.url))
        else:
            self.message(
                "Incremental replication of %d objects and %d links "
                "from %s to %s was successful." %
                (num_objects, num_links, SOURCE_DC, self.local_samdb.url))

    def run(self,
            DEST_DC,
            SOURCE_DC,
            NC,
            add_ref=False,
            sync_forced=False,
            sync_all=False,
            full_sync=False,
            local=False,
            local_online=False,
            async_op=False,
            single_object=False,
            sambaopts=None,
            credopts=None,
            versionopts=None):

        self.server = DEST_DC
        self.lp = sambaopts.get_loadparm()

        self.creds = credopts.get_credentials(self.lp, fallback_machine=True)

        if local:
            self.drs_local_replicate(SOURCE_DC,
                                     NC,
                                     full_sync=full_sync,
                                     single_object=single_object,
                                     sync_forced=sync_forced)
            return

        if local_online:
            server_bind = drsuapi.drsuapi("irpc:dreplsrv", lp_ctx=self.lp)
            server_bind_handle = misc.policy_handle()
        else:
            drsuapi_connect(self)
            server_bind = self.drsuapi
            server_bind_handle = self.drsuapi_handle

        if not async_op:
            # Give the sync replication 5 minutes time
            server_bind.request_timeout = 5 * 60

        samdb_connect(self)

        # we need to find the NTDS GUID of the source DC
        msg = self.samdb.search(
            base=self.samdb.get_config_basedn(),
            expression="(&(objectCategory=server)(|(name=%s)(dNSHostName=%s)))"
            % (ldb.binary_encode(SOURCE_DC), ldb.binary_encode(SOURCE_DC)),
            attrs=[])
        if len(msg) == 0:
            raise CommandError("Failed to find source DC %s" % SOURCE_DC)
        server_dn = msg[0]['dn']

        msg = self.samdb.search(
            base=server_dn,
            scope=ldb.SCOPE_ONELEVEL,
            expression="(|(objectCategory=nTDSDSA)(objectCategory=nTDSDSARO))",
            attrs=['objectGUID', 'options'])
        if len(msg) == 0:
            raise CommandError("Failed to find source NTDS DN %s" % SOURCE_DC)
        source_dsa_guid = msg[0]['objectGUID'][0]
        dsa_options = int(attr_default(msg, 'options', 0))

        req_options = 0
        if not (dsa_options & dsdb.DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL):
            req_options |= drsuapi.DRSUAPI_DRS_WRIT_REP
        if add_ref:
            req_options |= drsuapi.DRSUAPI_DRS_ADD_REF
        if sync_forced:
            req_options |= drsuapi.DRSUAPI_DRS_SYNC_FORCED
        if sync_all:
            req_options |= drsuapi.DRSUAPI_DRS_SYNC_ALL
        if full_sync:
            req_options |= drsuapi.DRSUAPI_DRS_FULL_SYNC_NOW
        if async_op:
            req_options |= drsuapi.DRSUAPI_DRS_ASYNC_OP

        try:
            drs_utils.sendDsReplicaSync(server_bind, server_bind_handle,
                                        source_dsa_guid, NC, req_options)
        except drs_utils.drsException as estr:
            raise CommandError("DsReplicaSync failed", estr)
        if async_op:
            self.message("Replicate from %s to %s was started." %
                         (SOURCE_DC, DEST_DC))
        else:
            self.message("Replicate from %s to %s was successful." %
                         (SOURCE_DC, DEST_DC))
Exemplo n.º 18
0
import tempfile
import samba
import samba.getopt as options
from samba.netcmd import Command, SuperCommand, CommandError, Option
from samba.samdb import SamDB
from samba.graph import dot_graph
from samba.graph import distance_matrix, COLOUR_SETS
from ldb import SCOPE_BASE, SCOPE_SUBTREE, LdbError
import time
from samba.kcc import KCC
from samba.kcc.kcc_utils import KCCError
from samba.compat import text_type

COMMON_OPTIONS = [
    Option("-H", "--URL", help="LDB URL for database or target server",
           type=str, metavar="URL", dest="H"),
    Option("-o", "--output", help="write here (default stdout)",
           type=str, metavar="FILE", default=None),
    Option("--dot", help="Graphviz dot output", dest='format',
           const='dot', action='store_const'),
    Option("--distance", help="Distance matrix graph output (default)",
           dest='format', const='distance', action='store_const'),
    Option("--utf8", help="Use utf-8 Unicode characters",
           action='store_true'),
    Option("--color", help="use color (yes, no, auto)",
           choices=['yes', 'no', 'auto']),
    Option("--color-scheme", help=("use this colour scheme "
                                   "(implies --color=yes)"),
           choices=list(COLOUR_SETS.keys())),
    Option("-S", "--shorten-names",
           help="don't print long common suffixes",