[Freeipa-devel] [PATCH] 0118 add support for subdomains

Sumit Bose sbose at redhat.com
Fri Sep 27 16:31:21 UTC 2013


On Fri, Sep 27, 2013 at 03:53:08PM +0300, Alexander Bokovoy wrote:
> On Mon, 23 Sep 2013, Alexander Bokovoy wrote:
> >On Mon, 23 Sep 2013, Alexander Bokovoy wrote:
> >>On Mon, 23 Sep 2013, Alexander Bokovoy wrote:
> >>>On Mon, 23 Sep 2013, Martin Kosek wrote:
> >>>>>>However, we don't have trust type available so it needs to discovered
> >>>>>>every time. This doesn't play well with the framework, it is simply not
> >>>>>>expecting dynamic containers.
> >>>>>
> >>>>>This doesn't sound like a big obstacle to me. Right now the trust_type lookup
> >>>>>is done in trust_show.execute() for some reason, which is not the best place to
> >>>>>do it IMHO. Doing it in trust.get_dn() instead should simplify things enough to
> >>>>>make parent_object work.
> >>>>
> >>>>Yup, get_dn() is the method where object DN lookup should be done. See for
> >>>>example host.py plugin get_dn method, we also do a dynamic lookup for correct
> >>>>host name.
> >>>I'll see if that would work.
> >>>
> >>>>the best way to implement dynamic DN gathering is the get_dn() method. That
> >>>>way, it could be implemented in one place and all commands could take advantage
> >>>>of it instead of re-implementing it several times in pre_callback - this is
> >>>>just hackish.
> >>>I'd suggest you look into the code. The commands use pre_callback for a
> >>>different purpose than implementing dynamic DN gathering.
> >>>
> >>>>I think it would have been very useful to have a design page before sending a
> >>>>patch. It is then easier to make design decisions without having to dig into
> >>>>the patch.
> >>>The design page is there for long time:
> >>>http://www.freeipa.org/page/V3/Transitive_Trusts
> >>Ok, here is new version of the patch and updated version of my 0117
> >>patch as Sumit noticed I've sent wrong version.
> >Ok, here is updated 0118 which fixes API.txt change for trustdomain_add
> >-- I renamed trustdomain_create to trustdomain_add but forgot to rerun
> >makeapi.
> New edition attached for all subdomain-related patches:

I did some tests and all is working as expected.

> 
> freeipa-abbra-0117-ipaserver-dcerpc.py-populate-forest-trust-informatio-3.patch
>   Use realmdomains to report name suffix routes at the time we establish trust
> 
> freeipa-abbra-0118-trusts-support-subdomains-in-a-forest-3.patch
>   Introduce trustdomain-* commands to fetch list of domains associated
>   with a forest trust and allow filtering them off

We talked on irc that ipaNTSupportedEncryptionTypes in the filter
for the trusted domains should be replace by a different attribute.
Because of an error in ipasam the ipaNTSupportedEncryptionTypes is only
set in recent versions and might not be present in the directory trees of
older versions.

bye,
Sumit
> 
> freeipa-abbra-0119-frontend-report-arguments-errors-with-better-detail.patch
>   Small fix to error reporting in parameters validation to show what
>   command produced an error and what was the context for it
> 
> freeipa-abbra-0120-ipaserver-dcerpc-remove-use-of-trust-account-authent.patch
>   Removal of trust account password use. We don't need it anymore as
>   KDC is now capable to produce MS-PAC for HTTP/ipa.master principal
> 
> freeipa-abbra-0121-trust-integrate-subdomains-support-into-trust-add.patch
>   Add automation for trust subdomains -- discover them at the time of
>   establishing trust and add ranges for non-POSIX case. In POSIX
>   attributes case no ranges are needed as trust idrange is used
>   instead.
> 
> freeipa-abbra-0122-ipasam-for-subdomains-pick-up-defaults-for-missing-v.patch
>   Make sure to fill in missing details for subdomains. Subdomains are
>   stored in the LDAP tree without information about trust type, direction,
>   and attributes as they are the same for subdomains and the trust root
>   domain.
> 
> 
> -- 
> / Alexander Bokovoy

> >From 5d0c5e8c4373fcfc92b4fa5113a554debb435073 Mon Sep 17 00:00:00 2001
> From: Alexander Bokovoy <abokovoy at redhat.com>
> Date: Wed, 11 Sep 2013 21:34:55 +0300
> Subject: [PATCH 1/7] ipaserver/dcerpc.py: populate forest trust information
>  using realmdomains
> 
> Use realmdomains information to prepopulate forest trust info. As result,
> all additional domains should now be enabled from the beginning, unless they
> really conflict with existing DNS domains on AD side.
> 
> https://fedorahosted.org/freeipa/ticket/3919
> ---
>  ipaserver/dcerpc.py | 113 +++++++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 95 insertions(+), 18 deletions(-)
> 
> diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
> index bd8f5aa..c24230b 100644
> --- a/ipaserver/dcerpc.py
> +++ b/ipaserver/dcerpc.py
> @@ -39,7 +39,7 @@ import uuid
>  from samba import param
>  from samba import credentials
>  from samba.dcerpc import security, lsa, drsblobs, nbt, netlogon
> -from samba.ndr import ndr_pack
> +from samba.ndr import ndr_pack, ndr_print
>  from samba import net
>  import samba
>  import random
> @@ -684,6 +684,12 @@ class DomainValidator(object):
>          self._info[domain] = info
>          return info
>  
> +def string_to_array(what):
> +    blob = [0] * len(what)
> +
> +    for i in range(len(what)):
> +        blob[i] = ord(what[i])
> +    return blob
>  
>  class TrustDomainInstance(object):
>  
> @@ -698,6 +704,7 @@ class TrustDomainInstance(object):
>          self._pipe = None
>          self._policy_handle = None
>          self.read_only = False
> +        self.ftinfo_records = None
>  
>      def __gen_lsa_connection(self, binding):
>         if self.creds is None:
> @@ -827,12 +834,6 @@ class TrustDomainInstance(object):
>          def arcfour_encrypt(key, data):
>              c = RC4.RC4(key)
>              return c.update(data)
> -        def string_to_array(what):
> -            blob = [0] * len(what)
> -
> -            for i in range(len(what)):
> -                blob[i] = ord(what[i])
> -            return blob
>  
>          password_blob = string_to_array(trustdom_secret.encode('utf-16-le'))
>  
> @@ -876,6 +877,53 @@ class TrustDomainInstance(object):
>          self.auth_info = auth_info
>  
>  
> +    def generate_ftinfo(self, another_domain):
> +        """
> +        Generates TrustDomainInfoFullInfo2Internal structure
> +        This structure allows to pass information about all domains associated
> +        with the another domain's realm.
> +
> +        Only top level name and top level name exclusions are handled here. 
> +        """
> +        if not another_domain.ftinfo_records:
> +            return
> +
> +        ftinfo_records = []
> +        info = lsa.ForestTrustInformation()
> +
> +        for rec in another_domain.ftinfo_records:
> +            record = lsa.ForestTrustRecord()
> +            record.flags = 0
> +            record.time = rec['rec_time']
> +            record.type = rec['rec_type']
> +            record.forest_trust_data.string = rec['rec_name']
> +            ftinfo_records.append(record)
> +
> +        info.count = len(ftinfo_records)
> +        info.entries = ftinfo_records
> +        return info
> +
> +    def update_ftinfo(self, another_domain):
> +        """
> +        Updates forest trust information in this forest corresponding
> +        to the another domain's information.
> +        """
> +        try:
> +            if another_domain.ftinfo_records:
> +                ftinfo = self.generate_ftinfo(another_domain)
> +                # Set forest trust information -- we do it only against AD DC as
> +                # smbd already has the information about itself
> +                ldname = lsa.StringLarge()
> +                ldname.string = another_domain.info['dns_domain']
> +                collision_info = self._pipe.lsaRSetForestTrustInformation(self._policy_handle,
> +                                                                          ldname,
> +                                                                          lsa.LSA_FOREST_TRUST_DOMAIN_INFO,
> +                                                                          ftinfo, 0)
> +                if collision_info:
> +                    root_logger.error("When setting forest trust information, got collision info back:\n%s" % (ndr_print(collision_info)))
> +        except RuntimeError, e:
> +            # We can ignore the error here -- setting up name suffix routes may fail
> +            pass
>  
>      def establish_trust(self, another_domain, trustdom_secret):
>          """
> @@ -883,6 +931,12 @@ class TrustDomainInstance(object):
>          Input: another_domain -- instance of TrustDomainInstance, initialized with #retrieve call
>                 trustdom_secret -- shared secred used for the trust
>          """
> +        if self.info['name'] == another_domain.info['name']:
> +            # Check that NetBIOS names do not clash
> +            raise errors.ValidationError(name=u'AD Trust Setup',
> +                    error=_('the IPA server and the remote domain cannot share the same '
> +                            'NetBIOS name: %s') % self.info['name'])
> +
>          self.generate_auth(trustdom_secret)
>  
>          info = lsa.TrustDomainInfoInfoEx()
> @@ -893,12 +947,6 @@ class TrustDomainInstance(object):
>          info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL
>          info.trust_attributes = lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
>  
> -        if self.info['name'] == info.netbios_name.string:
> -            # Check that NetBIOS names do not clash
> -            raise errors.ValidationError(name=u'AD Trust Setup',
> -                    error=_('the IPA server and the remote domain cannot share the same '
> -                            'NetBIOS name: %s') % self.info['name'])
> -
>          try:
>              dname = lsa.String()
>              dname.string = another_domain.info['dns_domain']
> @@ -911,12 +959,14 @@ class TrustDomainInstance(object):
>          except RuntimeError, (num, message):
>              raise assess_dcerpc_exception(num=num, message=message)
>  
> +        self.update_ftinfo(another_domain)
> +
> +        # We should use proper trustdom handle in order to modify the
> +        # trust settings. Samba insists this has to be done with LSA
> +        # OpenTrustedDomain* calls, it is not enough to have a handle
> +        # returned by the CreateTrustedDomainEx2 call.
> +        trustdom_handle = self._pipe.OpenTrustedDomainByName(self._policy_handle, dname, security.SEC_FLAG_MAXIMUM_ALLOWED)
>          try:
> -            # We should use proper trustdom handle in order to modify the
> -            # trust settings. Samba insists this has to be done with LSA
> -            # OpenTrustedDomain* calls, it is not enough to have a handle
> -            # returned by the CreateTrustedDomainEx2 call.
> -            trustdom_handle = self._pipe.OpenTrustedDomainByName(self._policy_handle, dname, security.SEC_FLAG_MAXIMUM_ALLOWED)
>              infoclass = lsa.TrustDomainInfoSupportedEncTypes()
>              infoclass.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5
>              infoclass.enc_types |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
> @@ -1016,6 +1066,32 @@ class TrustDomainJoins(object):
>          # Otherwise, use anonymously obtained data
>          self.remote_domain = rd
>  
> +    def get_realmdomains(self):
> +        """
> +        Generate list of records for forest trust information about
> +        our realm domains. Note that the list generated currently
> +        includes only top level domains, no exclusion domains, and no TDO objects
> +        as we handle the latter in a separte way
> +        """
> +        if self.local_domain.read_only:
> +            return
> +
> +	self.local_domain.ftinfo_records = []
> +
> +        realm_domains = self.api.Command.realmdomains_show()['result']
> +        trustconfig = self.api.Command.trustconfig_show()['result']
> +        # Use realmdomains' modification timestamp to judge records last update time
> +        (dn, entry_attrs) = self.api.Backend.ldap2.get_entry(realm_domains['dn'], ['modifyTimestamp'])
> +        # Convert the timestamp to Windows 64-bit timestamp format
> +        trust_timestamp = long(time.mktime(time.strptime(entry_attrs['modifytimestamp'][0][:14], "%Y%m%d%H%M%S"))*1e7+116444736000000000)
> +        
> +        for dom in realm_domains['associateddomain']:
> +            ftinfo = dict()
> +            ftinfo['rec_name'] = dom
> +            ftinfo['rec_time'] = trust_timestamp
> +            ftinfo['rec_type'] = lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME
> +            self.local_domain.ftinfo_records.append(ftinfo)
> +
>      def join_ad_full_credentials(self, realm, realm_server, realm_admin, realm_passwd):
>          if not self.configured:
>              return None
> @@ -1030,6 +1106,7 @@ class TrustDomainJoins(object):
>  
>          if not self.remote_domain.read_only:
>              trustdom_pass = samba.generate_random_password(128, 128)
> +            self.get_realmdomains()
>              self.remote_domain.establish_trust(self.local_domain, trustdom_pass)
>              self.local_domain.establish_trust(self.remote_domain, trustdom_pass)
>              result = self.remote_domain.verify_trust(self.local_domain)
> -- 
> 1.8.3.1
> 

> >From b077e4a0613fff8830388efab60ff0966877a7f6 Mon Sep 17 00:00:00 2001
> From: Alexander Bokovoy <abokovoy at redhat.com>
> Date: Wed, 18 Sep 2013 17:04:19 +0200
> Subject: [PATCH 2/7] trusts: support subdomains in a forest
> 
> Add IPA CLI to manage trust domains.
> 
> ipa trustdomain-fetch <trust>   -- fetch list of subdomains from AD side and add new ones to IPA
> ipa trustdomain-find <trust>    -- show all available domains
> ipa trustdomain-del <trust> <domain> -- remove domain from IPA view about <trust>
> 
> IPA KDC needs also information for authentication paths to subdomains in case they
> are not hierarchical under AD forest trust root. This information is managed via capaths
> section in krb5.conf. SSSD should be able to generate it once
> ticket https://fedorahosted.org/sssd/ticket/2093 is resolved.
> 
> part of https://fedorahosted.org/freeipa/ticket/3909
> ---
>  API.txt                 |  73 ++++++++++++
>  ipalib/plugins/trust.py | 295 +++++++++++++++++++++++++++++++++++++++---------
>  ipaserver/dcerpc.py     |  54 +++++++++
>  3 files changed, 370 insertions(+), 52 deletions(-)
> 
> diff --git a/API.txt b/API.txt
> index 761d1d1..674ff6c 100644
> --- a/API.txt
> +++ b/API.txt
> @@ -3497,6 +3497,79 @@ option: Str('version?', exclude='webui')
>  output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
>  output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
>  output: Output('value', <type 'unicode'>, None)
> +command: trustdomain_add
> +args: 2,9,3
> +arg: Str('trustcn', cli_name='trust', query=True, required=True)
> +arg: Str('cn', cli_name='domain')
> +option: Str('addattr*', cli_name='addattr', exclude='webui')
> +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
> +option: Str('ipantflatname', attribute=True, cli_name='flat_name', multivalue=False, required=False)
> +option: Str('ipanttrusteddomainsid', attribute=True, cli_name='sid', multivalue=False, required=False)
> +option: Str('ipanttrustpartner?')
> +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
> +option: Str('setattr*', cli_name='setattr', exclude='webui')
> +option: StrEnum('trust_type', autofill=True, cli_name='type', default=u'ad', values=(u'ad',))
> +option: Str('version?', exclude='webui')
> +output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
> +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
> +output: Output('value', <type 'unicode'>, None)
> +command: trustdomain_del
> +args: 2,2,3
> +arg: Str('trustcn', cli_name='trust', query=True, required=True)
> +arg: Str('cn', cli_name='domain')
> +option: Flag('continue', autofill=True, cli_name='continue', default=False)
> +option: Str('version?', exclude='webui')
> +output: Output('result', <type 'dict'>, None)
> +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
> +output: Output('value', <type 'unicode'>, None)
> +command: trustdomain_fetch
> +args: 1,4,2
> +arg: Str('trustcn', cli_name='trust', query=True, required=True)
> +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
> +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
> +option: Flag('rights', autofill=True, default=False)
> +option: Str('version?', exclude='webui')
> +output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None))
> +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
> +command: trustdomain_filter
> +args: 2,2,1
> +arg: Str('trustcn', cli_name='trust', query=True, required=True)
> +arg: Str('cn', cli_name='domain')
> +option: Flag('rights', autofill=True, default=False)
> +option: Str('version?', exclude='webui')
> +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
> +command: trustdomain_find
> +args: 2,7,4
> +arg: Str('trustcn', cli_name='trust', query=True, required=True)
> +arg: Str('criteria?', noextrawhitespace=False)
> +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
> +option: Str('ipantflatname', attribute=True, autofill=False, cli_name='flat_name', multivalue=False, query=True, required=False)
> +option: Str('ipanttrusteddomainsid', attribute=True, autofill=False, cli_name='sid', multivalue=False, query=True, required=False)
> +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
> +option: Int('sizelimit?', autofill=False, minvalue=0)
> +option: Int('timelimit?', autofill=False, minvalue=0)
> +option: Str('version?', exclude='webui')
> +output: Output('count', <type 'int'>, None)
> +output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None))
> +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
> +output: Output('truncated', <type 'bool'>, None)
> +command: trustdomain_mod
> +args: 2,10,3
> +arg: Str('trustcn', cli_name='trust', query=True, required=True)
> +arg: Str('cn', cli_name='domain')
> +option: Str('addattr*', cli_name='addattr', exclude='webui')
> +option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
> +option: Str('delattr*', cli_name='delattr', exclude='webui')
> +option: Str('ipantflatname', attribute=True, autofill=False, cli_name='flat_name', multivalue=False, required=False)
> +option: Str('ipanttrusteddomainsid', attribute=True, autofill=False, cli_name='sid', multivalue=False, required=False)
> +option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
> +option: Flag('rights', autofill=True, default=False)
> +option: Str('setattr*', cli_name='setattr', exclude='webui')
> +option: StrEnum('trust_type', autofill=True, cli_name='type', default=u'ad', values=(u'ad',))
> +option: Str('version?', exclude='webui')
> +output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
> +output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
> +output: Output('value', <type 'unicode'>, None)
>  command: user_add
>  args: 1,35,3
>  arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, required=True)
> diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
> index 3c117b4..bb3a023 100644
> --- a/ipalib/plugins/trust.py
> +++ b/ipalib/plugins/trust.py
> @@ -181,6 +181,13 @@ def trust_status_string(level):
>      string = _trust_status_dict.get(level, _trust_type_dict_unknown)
>      return unicode(string)
>  
> +def make_trust_dn(env, trust_type, dn):
> +    assert isinstance(dn, DN)
> +    if trust_type:
> +        container_dn = DN(('cn', trust_type), env.container_trusts, env.basedn)
> +        return DN(dn, container_dn)
> +    return dn
> +
>  class trust(LDAPObject):
>      """
>      Trust object.
> @@ -195,7 +202,8 @@ class trust(LDAPObject):
>          'ipantauthtrustoutgoing', 'ipanttrustauthincoming', 'ipanttrustforesttrustinfo',
>          'ipanttrustposixoffset', 'ipantsupportedencryptiontypes' ]
>      search_display_attributes = ['cn', 'ipantflatname',
> -                                 'ipanttrusteddomainsid', 'ipanttrusttype' ]
> +                                 'ipanttrusteddomainsid', 'ipanttrusttype',
> +                                 'ipantsidblacklistincoming', 'ipantsidblacklistoutgoing' ]
>  
>      label = _('Trusts')
>      label_singular = _('Trust')
> @@ -241,12 +249,24 @@ class trust(LDAPObject):
>                      raise errors.ValidationError(name=attr,
>                              error=_("invalid SID: %(value)s") % dict(value=value))
>  
> -def make_trust_dn(env, trust_type, dn):
> -    assert isinstance(dn, DN)
> -    if trust_type in trust.trust_types:
> -        container_dn = DN(('cn', trust_type), env.container_trusts, env.basedn)
> -        return DN(dn[0], container_dn)
> -    return dn
> +    def get_dn(self, *keys, **kwargs):
> +        sdn = map(lambda x: ('cn', x), keys)
> +        sdn.reverse()
> +        trust_type = kwargs.get('trust_type')
> +        if not trust_type:
> +            for ttype in self.trust_types:
> +                dn=make_trust_dn(self.env, ttype, DN(*sdn))
> +                try:
> +                    object_exists = self.backend.get_entry(dn, [''])
> +                    return object_exists.dn
> +                except errors.NotFound:
> +                    pass
> +            # if no trust object of any type exist, default to 'ad'
> +            # this is required for *_add calls.
> +            trust_type = u'ad'
> +
> +        dn=make_trust_dn(self.env, trust_type, DN(*sdn))
> +        return dn
>  
>  class trust_add(LDAPCreate):
>      __doc__ = _('''
> @@ -576,10 +596,13 @@ sides.
>      def execute_ad(self, full_join, *keys, **options):
>          # Join domain using full credentials and with random trustdom
>          # secret (will be generated by the join method)
> -        try:
> -            api.Command['trust_show'](keys[-1])
> +
> +        # First see if the trust is already in place
> +        # Force retrieval of the trust object by not passing trust_type
> +        dn = self.obj.get_dn(keys[-1], {})
> +        if dn:
>              summary = _('Re-established trust to domain "%(value)s"')
> -        except errors.NotFound:
> +        else:
>              summary = self.msg_summary
>  
>          # 1. Full access to the remote domain. Use admin credentials and
> @@ -652,14 +675,6 @@ class trust_del(LDAPDelete):
>  
>      msg_summary = _('Deleted trust "%(value)s"')
>  
> -    def pre_callback(self, ldap, dn, *keys, **options):
> -        assert isinstance(dn, DN)
> -        try:
> -            result = self.api.Command.trust_show(keys[-1])
> -        except errors.NotFound, e:
> -            self.obj.handle_not_found(*keys)
> -        return result['result']['dn']
> -
>  class trust_mod(LDAPUpdate):
>      __doc__ = _("""
>      Modify a trust (for future use).
> @@ -673,16 +688,10 @@ class trust_mod(LDAPUpdate):
>  
>      def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
>          assert isinstance(dn, DN)
> -        result = None
> -        try:
> -            result = self.api.Command.trust_show(keys[-1])
> -        except errors.NotFound, e:
> -            self.obj.handle_not_found(*keys)
>  
>          self.obj.validate_sid_blacklists(entry_attrs)
>  
> -        # TODO: we found the trust object, now modify it
> -        return result['result']['dn']
> +        return dn
>  
>  class trust_find(LDAPSearch):
>      __doc__ = _('Search for trusts.')
> @@ -696,8 +705,10 @@ class trust_find(LDAPSearch):
>      # Since all trusts types are stored within separate containers under 'cn=trusts',
>      # search needs to be done on a sub-tree scope
>      def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
> -        assert isinstance(base_dn, DN)
> -        return (filters, base_dn, ldap.SCOPE_SUBTREE)
> +        # list only trust, not trust domains
> +        trust_filter = '(ipaNTSupportedEncryptionTypes=*)'
> +        filter = ldap.combine_filters((filters, trust_filter), rules=ldap.MATCH_ALL)
> +        return (filter, base_dn, ldap.SCOPE_SUBTREE)
>  
>      def post_callback(self, ldap, entries, truncated, *args, **options):
>          if options.get('pkey_only', False):
> @@ -705,7 +716,7 @@ class trust_find(LDAPSearch):
>  
>          for entry in entries:
>              (dn, attrs) = entry
> -
> +            
>              # Translate ipanttrusttype to trusttype if --raw not used
>              if not options.get('raw', False):
>                  attrs['trusttype'] = trust_type_string(attrs['ipanttrusttype'][0])
> @@ -718,30 +729,6 @@ class trust_show(LDAPRetrieve):
>      has_output_params = LDAPRetrieve.has_output_params + trust_output_params +\
>                          (Str('ipanttrusttype'), Str('ipanttrustdirection'))
>  
> -    def execute(self, *keys, **options):
> -        error = None
> -        result = None
> -        for trust_type in trust.trust_types:
> -            options['trust_show_type'] = trust_type
> -            try:
> -                result = super(trust_show, self).execute(*keys, **options)
> -            except errors.NotFound, e:
> -                result = None
> -                error = e
> -            if result:
> -                break
> -        if error or not result:
> -            self.obj.handle_not_found(*keys)
> -
> -        return result
> -
> -    def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
> -        assert isinstance(dn, DN)
> -        if 'trust_show_type' in options:
> -            return make_trust_dn(self.env, options['trust_show_type'], dn)
> -
> -        return dn
> -
>      def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
>  
>          # Translate ipanttrusttype to trusttype
> @@ -1078,3 +1065,207 @@ class sidgen_was_run(Command):
>          return dict(result=True)
>  
>  api.register(sidgen_was_run)
> +
> +class trustdomain(LDAPObject):
> +    """
> +    Object representing a domain of the AD trust.
> +    """
> +    parent_object = 'trust'
> +    trust_type_idx = {'2':u'ad'}
> +    object_name = _('trust domain')
> +    object_name_plural = _('trust domains')
> +    object_class = ['ipaNTTrustedDomain']
> +    default_attributes = ['cn', 'ipantflatname', 'ipanttrusteddomainsid', 'ipanttrustpartner']
> +    search_display_attributes = ['cn', 'ipantflatname', 'ipanttrusteddomainsid', ]
> +
> +    label = _('Trusted domains')
> +    label_singular = _('Trusted domain')
> +
> +    # We do not add this argument implicitly via takes_args in the object.
> +    # Rather, it is added explicitly in the commands that require second arg
> +    # because first argument will be inherited from the 'trust' parent object
> +    trustdomain_args = (
> +        Str('cn',
> +            label=_('Domain name'),
> +            cli_name='domain',
> +        ),
> +    )
> +
> +    takes_params = (
> +        Str('ipantflatname?',
> +            cli_name='flat_name',
> +            label=_('Domain NetBIOS name'),
> +        ),
> +        Str('ipanttrusteddomainsid?',
> +            cli_name='sid',
> +            label=_('Domain Security Identifier'),
> +        ),
> +    )
> +
> +    # LDAPObject.get_dn() only passes all but last element of keys and no kwargs
> +    # to the parent object's get_dn() no matter what you pass to it. Make own get_dn()
> +    # as we really need all elements to construct proper dn.
> +    def get_dn(self, *keys, **kwargs):
> +        sdn = map(lambda x: ('cn', x), keys)
> +        sdn.reverse()
> +        trust_type = kwargs.get('trust_type')
> +        if not trust_type:
> +            trust_type=u'ad'
> +
> +        dn=make_trust_dn(self.env, trust_type, DN(*sdn))
> +        return dn
> +api.register(trustdomain)
> +
> +class trustdomain_find(LDAPSearch):
> +    __doc__ = _('Search domains of the trust')
> +
> +    def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
> +        return (filters, base_dn, ldap.SCOPE_SUBTREE)
> +api.register(trustdomain_find)
> +
> +class trustdomain_mod(LDAPUpdate):
> +    __doc__ = _('Modify trustdomain of the trust')
> +
> +    NO_CLI = True
> +    takes_args = trustdomain.trustdomain_args
> +    takes_options = LDAPUpdate.takes_options + (_trust_type_option,)
> +api.register(trustdomain_mod)
> +
> +class trustdomain_add(LDAPCreate):
> +    __doc__ = _('Allow access from the trusted domain')
> +    NO_CLI = True
> +
> +    takes_args = trustdomain.trustdomain_args
> +    takes_options = LDAPCreate.takes_options + (_trust_type_option,
> +        Str('ipanttrustpartner?',
> +            label=_('Trusted domain partner'),
> +        ),
> +    )
> +
> +    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
> +        if 'ipanttrustpartner' in options:
> +            entry_attrs['ipanttrustpartner'] = [options['ipanttrustpartner']]
> +        return dn
> +api.register(trustdomain_add)
> +
> +class trustdomain_del(LDAPDelete):
> +    __doc__ = _('Remove infromation about the domain associated with the trust.')
> +
> +    msg_summary = _('Removed information about the trusted domain "%(value)s"')
> +
> +    takes_args = trustdomain.trustdomain_args
> +    def execute(self, *keys, **options):
> +        result = super(trustdomain_del, self).execute(*keys, **options)
> +        result['value'] = keys[1]
> +        return result
> +
> +
> +api.register(trustdomain_del)
> +
> +
> +def fetch_domains_from_trust(self, trustinstance, trust_entry):
> +    trust_name = trust_entry['cn'][0]
> +    domains = ipaserver.dcerpc.fetch_domains(self.api, trustinstance.local_flatname, trust_name)
> +    result = []
> +    if not domains:
> +        return None
> +
> +    for dom in domains:
> +        dom['trust_type'] = u'ad'
> +        try:
> +            name = dom['cn']
> +            del dom['cn']
> +            res = self.api.Command.trustdomain_add(trust_name, name, **dom)
> +            result.append(res['result'])
> +        except errors.DuplicateEntry:
> +            # Ignore updating duplicate entries
> +            pass
> +    return result
> +
> +class trustdomain_fetch(LDAPRetrieve):
> +    __doc__ = _('Refresh list of the domains associated with the trust')
> +
> +    has_output = (
> +        output.ListOfEntries('result'),
> +        output.summary
> +    )
> +
> +    def execute(self, *keys, **options):
> +        if not _bindings_installed:
> +            raise errors.NotFound(
> +                name=_('AD Trust setup'),
> +                reason=_(
> +                    'Cannot perform join operation without Samba 4 support '
> +                    'installed. Make sure you have installed server-trust-ad '
> +                    'sub-package of IPA'
> +                )
> +            )
> +        trust = self.api.Command.trust_show(keys[0], raw=True)['result']
> +
> +        trustinstance = ipaserver.dcerpc.TrustDomainJoins(self.api)
> +        if not trustinstance.configured:
> +            raise errors.NotFound(
> +                name=_('AD Trust setup'),
> +                reason=_(
> +                    'Cannot perform join operation without own domain '
> +                    'configured. Make sure you have run ipa-adtrust-install '
> +                    'on the IPA server first'
> +                )
> +            )
> +        domains = fetch_domains_from_trust(self, trustinstance, trust)
> +        result = dict(result=[])
> +        if not domains:
> +            result['summary'] = unicode(_('No trust domains were detected during refresh'))
> +            return result
> +
> +        if len(domains) > 0:
> +            result['summary'] = unicode(_('List of trust domains successfully refreshed'))
> +        else:
> +            result['summary'] = unicode(_('No new trust domains were found'))
> +
> +        result['result'] = domains
> +        return result
> +api.register(trustdomain_fetch)
> +
> +class trustdomain_filter(LDAPRetrieve):
> +    __doc__ = _('Disable/allow use of IPA resources by the domain of the trust')
> +
> +    has_output = (
> +        output.summary,
> +    )
> +
> +    takes_args = trustdomain.trustdomain_args
> +
> +    def execute(self, *keys, **options):
> +        ldap = self.api.Backend.ldap2
> +
> +        try:
> +            trust = super(trustdomain_filter, self).execute(keys[0], **options)
> +            trust_dn = self.obj.get_dn(keys[0], trust_type=u'ad')
> +            trust_entry = ldap.get_entry(trust_dn)
> +        except errors.NotFound:
> +            raise errors.ValidationError(name=_('AD trust'), error=_('Valid trust name is required'))
> +
> +        result = dict()
> +        result['trust'] = unicode(keys[0])
> +        result['domain'] = unicode(keys[1])
> +        dn = self.obj.get_dn(keys[0], keys[1], trust_type=u'ad')
> +        try:
> +            entry = ldap.get_entry(dn)
> +            sid = entry['ipanttrusteddomainsid'][0]
> +            if sid in trust_entry['ipantsidblacklistincoming']:
> +                trust_entry['ipantsidblacklistincoming'].remove(sid)
> +                result['action'] = _('allowed')
> +            else:
> +                trust_entry['ipantsidblacklistincoming'].append(sid)
> +                result['action'] = _('not allowed')
> +            ldap.update_entry(trust_entry)
> +            result['summary'] = _('Domain %(domain)s of trust %(trust)s is %(action)s to access IPA resources')
> +        except errors.NotFound:
> +            raise errors.ValidationError(name=_('AD trust'), error=_('Valid trust domain name is required'))
> +        except errors.EmptyModlist:
> +            result['summary'] = _('No changes were done')
> +
> +        return dict(summary=result['summary'] % result)
> +
> +api.register(trustdomain_filter)
> diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
> index c24230b..af0e77e 100644
> --- a/ipaserver/dcerpc.py
> +++ b/ipaserver/dcerpc.py
> @@ -1002,6 +1002,60 @@ class TrustDomainInstance(object):
>              return True
>          return False
>  
> +def fetch_domains(api, mydomain, trustdomain):
> +    trust_flags = dict(
> +                NETR_TRUST_FLAG_IN_FOREST = 0x00000001,
> +                NETR_TRUST_FLAG_OUTBOUND  = 0x00000002,
> +                NETR_TRUST_FLAG_TREEROOT  = 0x00000004,
> +                NETR_TRUST_FLAG_PRIMARY   = 0x00000008,
> +                NETR_TRUST_FLAG_NATIVE    = 0x00000010,
> +                NETR_TRUST_FLAG_INBOUND   = 0x00000020,
> +                NETR_TRUST_FLAG_MIT_KRB5  = 0x00000080,
> +                NETR_TRUST_FLAG_AES       = 0x00000100)
> +
> +    trust_attributes = dict(
> +                NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE     = 0x00000001,
> +                NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY       = 0x00000002,
> +                NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN = 0x00000004,
> +                NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE  = 0x00000008,
> +                NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION = 0x00000010,
> +                NETR_TRUST_ATTRIBUTE_WITHIN_FOREST      = 0x00000020,
> +                NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL  = 0x00000040)
> +
> +    domval = DomainValidator(api)
> +    (ccache_name, principal) = domval.kinit_as_http(trustdomain)
> +    if ccache_name:
> +        with installutils.private_ccache(path=ccache_name):
> +            td = TrustDomainInstance('')
> +            td.parm.set('workgroup', mydomain)
> +            td.creds = credentials.Credentials()
> +            td.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
> +            td.creds.guess(td.parm)
> +            netrc = net.Net(creds=td.creds, lp=td.parm)
> +            try:
> +                result = netrc.finddc(domain=trustdomain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
> +            except RuntimeError, e:
> +                raise assess_dcerpc_exception(message=str(e))
> +            if not result:
> +                return None
> +            td.retrieve(unicode(result.pdc_dns_name))
> +
> +            netr_pipe = netlogon.netlogon(td.binding, td.parm, td.creds)
> +            domains = netr_pipe.netr_DsrEnumerateDomainTrusts(td.binding, 1)
> +
> +            result = []
> +            for t in domains.array:
> +                if ((t.trust_attributes & trust_attributes['NETR_TRUST_ATTRIBUTE_WITHIN_FOREST']) and
> +                    (t.trust_flags & trust_flags['NETR_TRUST_FLAG_IN_FOREST'])):
> +                    res = dict()
> +                    res['cn'] = unicode(t.dns_name)
> +                    res['ipantflatname'] = unicode(t.netbios_name)
> +                    res['ipanttrusteddomainsid'] = unicode(t.sid)
> +                    res['ipanttrustpartner'] = res['cn']
> +                    result.append(res)
> +            return result
> +
> +
>  class TrustDomainJoins(object):
>      def __init__(self, api):
>          self.api = api
> -- 
> 1.8.3.1
> 

> >From 9155190367c0543533746e6f5bc01c2609b4ec01 Mon Sep 17 00:00:00 2001
> From: Alexander Bokovoy <abokovoy at redhat.com>
> Date: Thu, 26 Sep 2013 16:44:37 +0200
> Subject: [PATCH 3/7] frontend: report arguments errors with better detail
> 
> When reporting argument errors, show also a context -- what is processed,
> what is the name of the command.
> ---
>  ipalib/frontend.py | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/ipalib/frontend.py b/ipalib/frontend.py
> index cac3e3b..f478ef0 100644
> --- a/ipalib/frontend.py
> +++ b/ipalib/frontend.py
> @@ -869,7 +869,8 @@ class Command(HasParam):
>          for arg in args():
>              if optional and arg.required:
>                  raise ValueError(
> -                    '%s: required argument after optional' % arg.name
> +                    '%s: required argument after optional in %s arguments %s' % (arg.name,
> +                    self.name, map(lambda x: x.param_spec, args()))
>                  )
>              if multivalue:
>                  raise ValueError(
> -- 
> 1.8.3.1
> 

> >From 0f91393b2c02a864eb4cc59f9a45ef466f24be56 Mon Sep 17 00:00:00 2001
> From: Alexander Bokovoy <abokovoy at redhat.com>
> Date: Fri, 27 Sep 2013 12:36:59 +0200
> Subject: [PATCH 4/7] ipaserver/dcerpc: remove use of trust account
>  authentication
> 
> Since FreeIPA KDC supports adding MS-PAC to HTTP/ipa.server principal,
> it is possible to use it when talking to the trusted AD DC.
> 
> Remove support for authenticating as trust account because it should not
> really be used other than within Samba.
> ---
>  ipalib/plugins/trust.py |  1 -
>  ipaserver/dcerpc.py     | 71 ++++---------------------------------------------
>  2 files changed, 5 insertions(+), 67 deletions(-)
> 
> diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
> index bb3a023..06ebd92 100644
> --- a/ipalib/plugins/trust.py
> +++ b/ipalib/plugins/trust.py
> @@ -536,7 +536,6 @@ sides.
>                                                            None,
>                                                            SCOPE_SUBTREE,
>                                                            basedn=info_dn,
> -                                                          use_http=True,
>                                                            quiet=True)
>  
>                  if info_list:
> diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
> index af0e77e..fa5c449 100644
> --- a/ipaserver/dcerpc.py
> +++ b/ipaserver/dcerpc.py
> @@ -165,8 +165,7 @@ class DomainValidator(object):
>                  base_dn=cn_trust,
>                  attrs_list=[self.ATTR_TRUSTED_SID,
>                              self.ATTR_FLATNAME,
> -                            self.ATTR_TRUST_PARTNER,
> -                            self.ATTR_TRUST_AUTHOUT]
> +                            self.ATTR_TRUST_PARTNER]
>                  )
>  
>              # We need to use case-insensitive dictionary since we use
> @@ -185,18 +184,8 @@ class DomainValidator(object):
>                                   "attribute: %s", dn, e)
>                      continue
>  
> -                trust_authout = entry.get(self.ATTR_TRUST_AUTHOUT, [None])[0]
> -
> -                # We were able to read all Trusted domain attributes but the
> -                # secret User is not member of trust admins group
> -                if trust_authout is None:
> -                    raise errors.ACIError(
> -                        info=_('communication with trusted domains is allowed '
> -                               'for Trusts administrator group members only'))
> -
>                  result[trust_partner] = (flatname_normalized,
> -                                         security.dom_sid(trusted_sid),
> -                                         trust_authout)
> +                                         security.dom_sid(trusted_sid))
>              return result
>          except errors.NotFound, e:
>              return []
> @@ -462,43 +451,6 @@ class DomainValidator(object):
>          ]
>          return u'S-%d-%d-%s' % ( sid_rev_num, ia, '-'.join([str(s) for s in subs]),)
>  
> -    def __extract_trusted_auth(self, info):
> -        """
> -        Returns in clear trusted domain account credentials
> -        """
> -        clear = None
> -        auth = drsblobs.trustAuthInOutBlob()
> -        auth.__ndr_unpack__(info['auth'])
> -        auth_array = auth.current.array[0]
> -        if auth_array.AuthType == lsa.TRUST_AUTH_TYPE_CLEAR:
> -            clear = ''.join(map(chr, auth_array.AuthInfo.password)).decode('utf-16-le')
> -        return clear
> -
> -    def __kinit_as_trusted_account(self, info, password):
> -        """
> -        Initializes ccache with trusted domain account credentials.
> -
> -        Applies session code defaults for ccache directory and naming prefix.
> -        Session code uses krbccache_prefix+<pid>, we use
> -        krbccache_prefix+<TD>+<domain netbios name> so there is no clash
> -
> -        Returns tuple (ccache name, principal) where (None, None) signifes an error
> -        on ccache initialization
> -        """
> -        ccache_name = os.path.join(krbccache_dir, "%sTD%s" % (krbccache_prefix, info['name'][0]))
> -        principal = '%s$@%s' % (self.flatname, info['dns_domain'].upper())
> -        (stdout, stderr, returncode) = ipautil.run(['/usr/bin/kinit', principal],
> -                                                   env={'KRB5CCNAME':ccache_name},
> -                                                   stdin=password, raiseonerr=False)
> -        if returncode == 0:
> -            return (ccache_name, principal)
> -        else:
> -            if returncode == 1:
> -                raise errors.ACIError(
> -                   info=_("KDC for %(domain)s denied trust account for IPA domain with a message '%(message)s'") %
> -                        dict(domain=info['dns_domain'],message=stderr.strip()))
> -            return (None, None)
> -
>      def kinit_as_http(self, domain):
>          """
>          Initializes ccache with http service credentials.
> @@ -544,13 +496,10 @@ class DomainValidator(object):
>              return (None, None)
>  
>      def search_in_dc(self, domain, filter, attrs, scope, basedn=None,
> -                     use_http=False, quiet=False):
> +                     quiet=False):
>          """
>          Perform LDAP search in a trusted domain `domain' Domain Controller.
>          Returns resulting entries or None.
> -
> -        If use_http is set to True, the search is conducted using
> -        HTTP service credentials.
>          """
>  
>          entries = None
> @@ -565,7 +514,6 @@ class DomainValidator(object):
>          for (host, port) in info['gc']:
>              entries = self.__search_in_dc(info, host, port, filter, attrs,
>                                            scope, basedn=basedn,
> -                                          use_http=use_http,
>                                            quiet=quiet)
>              if entries:
>                  break
> @@ -573,22 +521,13 @@ class DomainValidator(object):
>          return entries
>  
>      def __search_in_dc(self, info, host, port, filter, attrs, scope,
> -                       basedn=None, use_http=False, quiet=False):
> +                       basedn=None, quiet=False):
>          """
>          Actual search in AD LDAP server, using SASL GSSAPI authentication
>          Returns LDAP result or None.
>          """
>  
> -        if use_http:
> -            (ccache_name, principal) = self.kinit_as_http(info['dns_domain'])
> -        else:
> -            auth = self.__extract_trusted_auth(info)
> -
> -            if not auth:
> -                return None
> -
> -            (ccache_name, principal) = self.__kinit_as_trusted_account(info,
> -                                                                       auth)
> +        (ccache_name, principal) = self.kinit_as_http(info['dns_domain'])
>  
>          if ccache_name:
>              with installutils.private_ccache(path=ccache_name):
> -- 
> 1.8.3.1
> 

> >From cb695d12b638f23a2743ac97c792625a065fc8f0 Mon Sep 17 00:00:00 2001
> From: Alexander Bokovoy <abokovoy at redhat.com>
> Date: Fri, 27 Sep 2013 12:39:57 +0200
> Subject: [PATCH 5/7] trust: integrate subdomains support into trust-add
> 
> ---
>  ipalib/plugins/trust.py | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
> index 06ebd92..771a92b 100644
> --- a/ipalib/plugins/trust.py
> +++ b/ipalib/plugins/trust.py
> @@ -343,7 +343,17 @@ sides.
>                           base_dn = DN(api.env.container_trusts, api.env.basedn),
>                           filter = trust_filter)
>  
> +
>          result['result'] = entry_to_dict(trusts[0][1], **options)
> +        if options.get('trust_type') == u'ad':
> +            domains = fetch_domains_from_trust(self, self.trustinstance, result['result'])
> +            if domains and len(domains) > 0:
> +                for dom in domains:
> +                    range_name = dom['cn'][0].upper() + '_id_range'
> +                    range_type=options.get('range_type', u'ipa-ad-trust')
> +                    dom_sid = dom['ipanttrusteddomainsid'][0]
> +                    self.add_range(range_name, dom_sid, range_type=range_type)
> +
>          result['result']['trusttype'] = [trust_type_string(result['result']['ipanttrusttype'][0])]
>          result['result']['trustdirection'] = [trust_direction_string(result['result']['ipanttrustdirection'][0])]
>          result['result']['truststatus'] = [trust_status_string(result['verified'])]
> @@ -431,7 +441,7 @@ sides.
>          except errors.NotFound:
>              old_range = None
>  
> -        if options.get('type') == u'ad':
> +        if options.get('trust_type') == u'ad':
>              if range_type and range_type not in (u'ipa-ad-trust',
>                                                   u'ipa-ad-trust-posix'):
>                  raise errors.ValidationError(
> -- 
> 1.8.3.1
> 

> >From cccde6f77aaf95593400c2804f1bcca26564fdca Mon Sep 17 00:00:00 2001
> From: Alexander Bokovoy <abokovoy at redhat.com>
> Date: Fri, 27 Sep 2013 14:00:22 +0200
> Subject: [PATCH 7/7] ipasam: for subdomains pick up defaults for missing
>  values
> 
> We don't store trust type, attributes, and direction for subdomains
> of the existing trust. Since trust is always forest level, these parameters
> can be added as defaults when they are missing.
> ---
>  daemons/ipa-sam/ipa_sam.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
> index a535c0f..59ddcef 100644
> --- a/daemons/ipa-sam/ipa_sam.c
> +++ b/daemons/ipa-sam/ipa_sam.c
> @@ -2026,6 +2026,10 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx,
>  	if (!res) {
>  		return false;
>  	}
> +	if (td->trust_direction == 0) {
> +		/* attribute wasn't present, set default value */
> +		td->trust_direction = LSA_TRUST_DIRECTION_INBOUND | LSA_TRUST_DIRECTION_OUTBOUND;
> +	}
>  
>  	res = get_uint32_t_from_ldap_msg(ldap_state, entry,
>  					 LDAP_ATTRIBUTE_TRUST_ATTRIBUTES,
> @@ -2033,6 +2037,10 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx,
>  	if (!res) {
>  		return false;
>  	}
> +	if (td->trust_attributes == 0) {
> +		/* attribute wasn't present, set default value */
> +		td->trust_attributes = LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE;
> +	}
>  
>  	res = get_uint32_t_from_ldap_msg(ldap_state, entry,
>  					 LDAP_ATTRIBUTE_TRUST_TYPE,
> @@ -2040,6 +2048,10 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx,
>  	if (!res) {
>  		return false;
>  	}
> +	if (td->trust_type == 0) {
> +		/* attribute wasn't present, set default value */
> +		td->trust_type = LSA_TRUST_TYPE_UPLEVEL;
> +	}
>  
>  	td->trust_posix_offset = talloc_zero(td, uint32_t);
>  	if (td->trust_posix_offset == NULL) {
> -- 
> 1.8.3.1
> 

> _______________________________________________
> Freeipa-devel mailing list
> Freeipa-devel at redhat.com
> https://www.redhat.com/mailman/listinfo/freeipa-devel




More information about the Freeipa-devel mailing list