[Freeipa-devel] [PATCH] 0060 Ensure ipa-adtrust-install is run as admin user

Alexander Bokovoy abokovoy at redhat.com
Fri Jul 13 17:33:54 UTC 2012


On Fri, 13 Jul 2012, Alexander Bokovoy wrote:
> Hi,
> 
> when adding AD trusts support, we need to ensure we have valid kerberos
> ticket of the user from 'admins' group or otherwise appropriate ACIs
> will not be granted.
> 
> This patch introduces a check for that. We already check if
> ipa-adtrust-install is run by root so this complements existing checks.
> 
> https://fedorahosted.org/freeipa/ticket/2815
After discussing on IRC with Simo and Rob, we came to conclusion that it
is possible to switch to LDAPI and autobind feature of dirsrv for
authentication and remove requirement for Directory Manager credentials
altogether.

Updated patch makes use of LDAPI + autobind under root privileges to map
automatically to Directory Manager privileges in dirsrv. Additionally it
ensures we have Kerberos credentials to fetch keytab with CIFS service
key.

Service._ldap_mod() is extended to switch to autobind when self.ldapi is
set to True and we are running as root.

For those interested in why ACIError is mapped to 'outdated Kerberos
credentials' error message, this is because we'll get ACIError for 
'ipa user-show <uid>' command when authenticated by the Kerberos credentials
for <uid> in a default ccache only when Kerberos credentials are stale --
either belong to a user that was removed or to a previous IPA install
that was wiped before reinstalling. The latter is how I discovered
this case. :)

-- 
/ Alexander Bokovoy
-------------- next part --------------
>From 7e4216272fffe55a8f87c51c418895fe6b4dbd73 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy at redhat.com>
Date: Fri, 13 Jul 2012 18:12:48 +0300
Subject: [PATCH 2/2] Ensure ipa-adtrust-install is run with Kerberos ticket
 for admin user

When setting up AD trusts support, ipa-adtrust-install utility
needs to be run as:
   - root, for performing Samba configuration and using LDAPI/autobind
   - kinit-ed IPA admin user, to ensure proper ACIs are granted to
     fetch keytab

As result, we can get rid of Directory Manager credentials in ipa-adtrust-install

https://fedorahosted.org/freeipa/ticket/2815
---
 install/tools/ipa-adtrust-install       |   42 +++++++++++++++++++++++--------
 install/tools/man/ipa-adtrust-install.1 |    3 ---
 ipaserver/install/adtrustinstance.py    |   21 ++++++++--------
 ipaserver/install/service.py            |   15 +++++++++--
 4 files changed, 55 insertions(+), 26 deletions(-)

diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install
index 6678018e6346d75d5042894cfb833d38079d3f21..f367d5b2b516bd411bce9275ff299eb3ffdf6bf9 100755
--- a/install/tools/ipa-adtrust-install
+++ b/install/tools/ipa-adtrust-install
@@ -37,8 +37,6 @@ log_file_name = "/var/log/ipaserver-install.log"
 
 def parse_options():
     parser = IPAOptionParser(version=version.VERSION)
-    parser.add_option("-p", "--ds-password", dest="dm_password",
-                      sensitive=True, help="directory manager password")
     parser.add_option("-d", "--debug", dest="debug", action="store_true",
                       default=False, help="print debugging information")
     parser.add_option("--ip-address", dest="ip_address",
@@ -86,6 +84,30 @@ def read_netbios_name(netbios_default):
 
     return netbios_name
 
+def ensure_kerberos_admin_rights(api):
+    try:
+        ctx = krbV.default_context()
+        ccache = ctx.default_ccache()
+        principal = ccache.principal()
+        api.Backend.ldap2.connect(ccache.name)
+        user = api.Command.user_show(unicode(principal[0]))['result']
+        group = api.Command.group_show(u'admins')['result']
+        api.Backend.ldap2.disconnect()
+        if not (user['uid'][0] in group['member_user'] and
+                group['cn'][0] in user['memberof_group']):
+            raise errors.RequirementError(name='admins group membership')
+    except Exception, e:
+        error_messages = dict(
+           ACIError = "Outdated Kerberos credentials. Use kdestroy and kinit to update your ticket",
+           Krb5Error = "Must have Kerberos credentials to setup AD trusts on server",
+           RequirementError = "Must have administrative privileges to setup AD trusts on server"
+        )
+        name = type(e).__name__
+        if name in error_messages:
+            sys.exit(error_messages[name])
+        else:
+            sys.exit("Unrecognized error during check of admin rights: %s\n%s" % (name, str(e)))
+
 def main():
     safe_options, options = parse_options()
 
@@ -128,6 +150,8 @@ def main():
     api.bootstrap(**cfg)
     api.finalize()
 
+    ensure_kerberos_admin_rights(api)
+
     if adtrustinstance.ipa_smb_conf_exists():
         if not options.unattended:
             while True:
@@ -194,9 +218,8 @@ def main():
     if not options.unattended and ( not netbios_name or not options.netbios_name):
         netbios_name = read_netbios_name(netbios_name)
 
-    dm_password = options.dm_password or read_password("Directory Manager",
-                                             confirm=False, validate=False)
-    smb = adtrustinstance.ADTRUSTInstance(fstore, dm_password)
+    smb = adtrustinstance.ADTRUSTInstance(fstore)
+    smb.realm = api.env.realm
 
     # try the connection
     try:
@@ -205,12 +228,9 @@ def main():
     except ldap.INVALID_CREDENTIALS, e:
         sys.exit("Password is not valid!")
 
-    if smb.dm_password:
-        api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=smb.dm_password)
-    else:
-        # See if our LDAP server is up and we can talk to it over GSSAPI
-        ccache = krbV.default_context().default_ccache().name
-        api.Backend.ldap2.connect(ccache)
+    # See if our LDAP server is up and we can talk to it over GSSAPI
+    ccache = krbV.default_context().default_ccache().name
+    api.Backend.ldap2.connect(ccache)
 
     smb.setup(api.env.host, ip_address, api.env.realm, api.env.domain,
               netbios_name, options.rid_base, options.secondary_rid_base,
diff --git a/install/tools/man/ipa-adtrust-install.1 b/install/tools/man/ipa-adtrust-install.1
index b61da19088b40d6a9e53784f9a061913ecda4321..22337c3df8827670657bf405b6c49ba2f8624d6d 100644
--- a/install/tools/man/ipa-adtrust-install.1
+++ b/install/tools/man/ipa-adtrust-install.1
@@ -27,9 +27,6 @@ trust to an Active Directory domain. This requires that the IPA server is
 already installed and configured.
 .SH "OPTIONS"
 .TP
-\fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-ds\-password\fR=\fIDM_PASSWORD\fR
-The password to be used by the Directory Server for the Directory Manager user
-.TP
 \fB\-d\fR, \fB\-\-debug\fR
 Enable debug logging when more verbose output is needed
 .TP
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index 20feec4df309b5793aa1c29fdf18bc5bfe180943..9dcbec2d61d935f90e74cc65b30a0f1d0c0f9d2a 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -96,10 +96,9 @@ class ADTRUSTInstance(service.Service):
     OBJC_GROUP = "ipaNTGroupAttrs"
     OBJC_DOMAIN = "ipaNTDomainAttrs"
 
-    def __init__(self, fstore=None, dm_password=None):
+    def __init__(self, fstore=None):
         self.fqdn = None
         self.ip_address = None
-        self.realm_name = None
         self.domain_name = None
         self.netbios_name = None
         self.no_msdcs = None
@@ -118,7 +117,7 @@ class ADTRUSTInstance(service.Service):
         self.rid_base = None
         self.secondary_rid_base = None
 
-        service.Service.__init__(self, "smb", dm_password=dm_password)
+        service.Service.__init__(self, "smb", dm_password=None, ldapi=True)
 
         if fstore:
             self.fstore = fstore
@@ -436,6 +435,8 @@ class ADTRUSTInstance(service.Service):
         # We do not let the system start IPA components on its own,
         # Instead we reply on the IPA init script to start only enabled
         # components as found in our LDAP configuration tree
+        # Note that self.dm_password is None for ADTrustInstance because
+        # we ensure to be called as root and using ldapi to use autobind
         try:
             self.ldap_enable('ADTRUST', self.fqdn, self.dm_password, \
                              self.suffix)
@@ -449,7 +450,7 @@ class ADTRUSTInstance(service.Service):
             root_logger.info("EXTID Service startup entry already exists.")
 
     def __setup_sub_dict(self):
-        self.sub_dict = dict(REALM = self.realm_name,
+        self.sub_dict = dict(REALM = self.realm,
                              SUFFIX = self.suffix,
                              NETBIOS_NAME = self.netbios_name,
                              SMB_DN = self.smb_dn,
@@ -460,16 +461,16 @@ class ADTRUSTInstance(service.Service):
               rid_base, secondary_rid_base, no_msdcs=False, smbd_user="samba"):
         self.fqdn = fqdn
         self.ip_address = ip_address
-        self.realm_name = realm_name
+        self.realm = realm_name
         self.domain_name = domain_name
         self.netbios_name = netbios_name
         self.rid_base = rid_base
         self.secondary_rid_base = secondary_rid_base
         self.no_msdcs = no_msdcs
         self.smbd_user = smbd_user
-        self.suffix = ipautil.realm_to_suffix(self.realm_name)
+        self.suffix = ipautil.realm_to_suffix(self.realm)
         self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \
-                            realm_to_serverid(self.realm_name)
+                            realm_to_serverid(self.realm)
 
         self.smb_conf = "/etc/samba/smb.conf"
 
@@ -479,7 +480,7 @@ class ADTRUSTInstance(service.Service):
         self.trust_dn = str(DN(api.env.container_trusts, self.suffix))
         self.smb_dom_dn = str(DN(('cn', self.domain_name),
                                  api.env.container_cifsdomains, self.suffix))
-        self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm_name
+        self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm
         self.cifs_agent = str(DN(('krbprincipalname', self.cifs_principal.lower()),
                                  api.env.container_service,
                                  self.suffix))
@@ -522,11 +523,11 @@ class ADTRUSTInstance(service.Service):
                              "range.\nAdd local ID range manually and try " \
                              "again!")
 
-        entry = ipaldap.Entry(str(DN(('cn', ('%s_id_range' % self.realm_name)),
+        entry = ipaldap.Entry(str(DN(('cn', ('%s_id_range' % self.realm)),
                                      api.env.container_ranges,
                                      self.suffix)))
         entry.setValue('objectclass', 'ipaDomainIDRange')
-        entry.setValue('cn', ('%s_id_range' % self.realm_name))
+        entry.setValue('cn', ('%s_id_range' % self.realm))
         entry.setValue('ipaBaseID', str(base_id))
         entry.setValue('ipaIDRangeSize', str(id_range_size))
         self.admin_conn.addEntry(entry)
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index 5c2699e3fa4c115c972528d4c2cc6aa170711837..f96c21005ee69675ced4513b1b37272715482336 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -107,15 +107,26 @@ class Service(object):
             if sub_dict.has_key('RANDOM_PASSWORD'):
                 nologlist.append(sub_dict['RANDOM_PASSWORD'])
 
+        args = ["/usr/bin/ldapmodify", "-v", "-f", path]
+
+        # Support autobind when running as root and using ldapi
+        if self.ldapi:
+            if not self.admin_conn:
+                self.ldap_connect()
+            args += ["-H", self.admin_conn._uri]
+        else:
+            args += ["-h", hostname]
+
         if self.dm_password:
             [pw_fd, pw_name] = tempfile.mkstemp()
             os.write(pw_fd, self.dm_password)
             os.close(pw_fd)
             auth_parms = ["-x", "-D", "cn=Directory Manager", "-y", pw_name]
         else:
-            auth_parms = ["-Y", "GSSAPI"]
+            auth_params = []
+            if not (os.getegid() == 0 and self.ldapi):
+                auth_parms = ["-Y", "GSSAPI"]
 
-        args = ["/usr/bin/ldapmodify", "-h", hostname, "-v", "-f", path]
         args += auth_parms
 
         try:
-- 
1.7.10.4



More information about the Freeipa-devel mailing list