Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport ipa-4-6] Trust pass args and options #2977

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion API.txt
Expand Up @@ -5765,10 +5765,12 @@ output: Output('result', type=[<type 'dict'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: ListOfPrimaryKeys('value')
command: trust_fetch_domains/1
args: 1,5,4
args: 1,7,4
arg: Str('cn', cli_name='realm')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Str('realm_admin?', cli_name='admin')
option: Password('realm_passwd?', cli_name='password', confirm=False)
option: Str('realm_server?', cli_name='server')
option: Flag('rights', autofill=True, default=False)
option: Str('version?')
Expand Down
4 changes: 2 additions & 2 deletions VERSION.m4
Expand Up @@ -82,8 +82,8 @@ define(IPA_DATA_VERSION, 20100614120000)
# #
########################################################
define(IPA_API_VERSION_MAJOR, 2)
define(IPA_API_VERSION_MINOR, 230)
# Last change: Added `automember-find-orphans' command
define(IPA_API_VERSION_MINOR, 231)
# Last change: Added admin creds to trust-fetch-domains


########################################################
Expand Down
91 changes: 51 additions & 40 deletions install/oddjob/com.redhat.idm.trust-fetch-domains
Expand Up @@ -14,11 +14,31 @@ import pwd
import six
import gssapi

from ipalib.install.kinit import kinit_keytab
from ipalib.install.kinit import kinit_keytab, kinit_password

if six.PY3:
unicode = str


def parse_options():
usage = "%prog <trusted domain name>\n"
parser = config.IPAOptionParser(usage=usage,
formatter=config.IPAFormatter())

parser.add_option("-d", "--debug", action="store_true", dest="debug",
help="Display debugging information")
parser.add_option("-s", "--server", action="store", dest="server",
help="Domain controller for the Active Directory domain (optional)")
parser.add_option("-a", "--admin", action="store", dest="admin",
help="Active Directory administrator (optional)")
parser.add_option("-p", "--password", action="store", dest="password",
help="Display debugging information")

options, args = parser.parse_args()
safe_options = parser.get_safe_opts(options)

return safe_options, options, args

def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
getkeytab_args = ["/usr/sbin/ipa-getkeytab",
"-s", api.env.host,
Expand All @@ -40,7 +60,7 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
pass


def get_forest_root_domain(api_instance, trusted_domain):
def get_forest_root_domain(api_instance, trusted_domain, server=None):
"""
retrieve trusted forest root domain for given domain name

Expand All @@ -53,25 +73,11 @@ def get_forest_root_domain(api_instance, trusted_domain):
flatname = trustconfig_show()['result']['ipantflatname'][0]

remote_domain = dcerpc.retrieve_remote_domain(
api_instance.env.host, flatname, trusted_domain)
api_instance.env.host, flatname, trusted_domain,
realm_server=server)

return remote_domain.info['dns_forest']


def parse_options():
usage = "%prog <trusted domain name>\n"
parser = config.IPAOptionParser(usage=usage,
formatter=config.IPAFormatter())

parser.add_option("-d", "--debug", action="store_true", dest="debug",
help="Display debugging information")

options, args = parser.parse_args()
safe_options = parser.get_safe_opts(options)

return safe_options, options, args


if not is_ipa_configured():
# LSB status code 6: program is not configured
raise ScriptError("IPA is not configured " +
Expand Down Expand Up @@ -153,42 +159,47 @@ trusted_domain = trusted_domain_entry.single_value.get('cn').lower()
# At this point if we didn't find trusted forest name, an exception will be raised
# and script will quit. This is actually intended.

oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper()))
if not (options.admin and options.password):
oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper()))

# If keytab does not exist, retrieve it
if not os.path.isfile(oneway_keytab_name):
retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
# If keytab does not exist, retrieve it
if not os.path.isfile(oneway_keytab_name):
retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)

try:
have_ccache = False
try:
# The keytab may have stale key material (from older trust-add run)
cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
if cred.lifetime > 0:
have_ccache = True
except gssapi.exceptions.ExpiredCredentialsError:
pass
if not have_ccache:
have_ccache = False
try:
# The keytab may have stale key material (from older trust-add run)
cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
if cred.lifetime > 0:
have_ccache = True
except gssapi.exceptions.ExpiredCredentialsError:
pass
if not have_ccache:
if os.path.exists(oneway_ccache_name):
os.unlink(oneway_ccache_name)
kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
except gssapi.exceptions.GSSError:
# If there was failure on using keytab, assume it is stale and retrieve again
retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
if os.path.exists(oneway_ccache_name):
os.unlink(oneway_ccache_name)
kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
except gssapi.exceptions.GSSError:
# If there was failure on using keytab, assume it is stale and retrieve again
retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
if os.path.exists(oneway_ccache_name):
os.unlink(oneway_ccache_name)
kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
else:
cred = kinit_password(options.admin, options.password,
oneway_ccache_name,
canonicalize=True, enterprise=True)

# We are done: we have ccache with TDO credentials and can fetch domains
ipa_domain = api.env.domain
os.environ['KRB5CCNAME'] = oneway_ccache_name

# retrieve the forest root domain name and contact it to retrieve trust
# topology info
forest_root = get_forest_root_domain(api, trusted_domain)
forest_root = get_forest_root_domain(api, trusted_domain, server=options.server)

domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True)
domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True, server=options.server)
trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)['result']
trust.add_new_domains_from_trust(api, None, trust_domain_object, domains)

Expand Down
2 changes: 1 addition & 1 deletion install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf
Expand Up @@ -11,7 +11,7 @@
<interface name="com.redhat.idm.trust">
<method name="fetch_domains">
<helper exec="/usr/libexec/ipa/oddjob/com.redhat.idm.trust-fetch-domains"
arguments="1"
arguments="30"
argument_passing_method="cmdline"
prepend_user_name="no"/>
</method>
Expand Down
31 changes: 26 additions & 5 deletions ipaserver/plugins/trust.py
Expand Up @@ -418,9 +418,19 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
return range_type, range_size, base_id


def fetch_trusted_domains_over_dbus(myapi, forest_name):
def fetch_trusted_domains_over_dbus(myapi, *keys, **options):
if not _bindings_installed:
return

forest_name = keys[0]
method_options = []
if 'realm_server' in options:
method_options.extend(['--server', options['realm_server']])
if 'realm_admin' in options:
method_options.extend(['--admin', options['realm_admin']])
if 'realm_passwd' in options:
method_options.extend(['--password', options['realm_passwd']])

# Calling oddjobd-activated service via DBus has some quirks:
# - Oddjobd registers multiple canonical names on the same address
# - python-dbus only follows name owner changes when mainloop is in use
Expand All @@ -436,7 +446,8 @@ def fetch_trusted_domains_over_dbus(myapi, forest_name):
fetch_domains_method = intf.get_dbus_method(
'fetch_domains',
dbus_interface=DBUS_IFACE_TRUST)
(_ret, _stdout, _stderr) = fetch_domains_method(forest_name)
(_ret, _stdout, _stderr) = fetch_domains_method(
[forest_name] + method_options)
except dbus.DBusException as e:
logger.error('Failed to call %s.fetch_domains helper.'
'DBus exception is %s.', DBUS_IFACE_TRUST, str(e))
Expand Down Expand Up @@ -1760,10 +1771,20 @@ class trust_fetch_domains(LDAPRetrieve):

has_output = output.standard_list_of_entries
takes_options = LDAPRetrieve.takes_options + (
Str('realm_admin?',
cli_name='admin',
label=_("Active Directory domain administrator"),
),
Password('realm_passwd?',
cli_name='password',
label=_("Active Directory domain administrator's password"),
confirm=False,
),
Str('realm_server?',
cli_name='server',
label=_('Domain controller for the Active Directory domain (optional)'),
),
label=_('Domain controller for the Active Directory domain '
'(optional)'),
),
)

def execute(self, *keys, **options):
Expand All @@ -1784,7 +1805,7 @@ def execute(self, *keys, **options):
# With privilege separation we also cannot authenticate as
# HTTP/ principal because we have no access to its key material.
# Thus, we'll use DBus call out to oddjobd helper in all cases
fetch_trusted_domains_over_dbus(self.api, keys[0])
fetch_trusted_domains_over_dbus(self.api, *keys, **options)
result['summary'] = unicode(_('List of trust domains successfully '
'refreshed. Use trustdomain-find '
'command to list them.'))
Expand Down