On Wed, 18 Jul 2012, Alexander Bokovoy wrote:
On Tue, 17 Jul 2012, Rob Crittenden wrote:
Alexander Bokovoy wrote:
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. :)

I think that this should raise an exception if one tries to use ldapi, doesn't provide the DM password and is not root. Otherwise it won't authenticate at all.
This is not exactly true.

$ id
uid=757000001(abokovoy) gid=757000001(abokovoy) groups=757000001(abokovoy)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

$ ldapsearch -vvv -H ldapi://%2fvar%2frun%2fslapd-IPA-LOCAL.socket '*' 
>/dev/null
ldap_initialize( ldapi://%2Fvar%2Frun%2Fslapd-IPA-LOCAL.socket/??base )
SASL/EXTERNAL authentication started
ldap_sasl_interactive_bind_s: Inappropriate authentication (48)
        additional info: SASL EXTERNAL bind requires an SSL connection

$ ldapsearch -vvv -Y GSSAPI -H ldapi://%2fvar%2frun%2fslapd-IPA-LOCAL.socket '*' 
>/dev/null
ldap_initialize( ldapi://%2Fvar%2Frun%2Fslapd-IPA-LOCAL.socket/??base )
SASL/GSSAPI authentication started
SASL username: abokovoy@IPA.LOCAL
SASL SSF: 56
SASL data security layer installed.
filter: (objectclass=*)
requesting: *

So GSSAPI auth works with LDAPI access. I can simply enforce -Y GSSAPI
when non-root and no dm_password regardless of self.ldapi, this would
extend previously available logic to following:

- ldapi: use -H ldapi://url instead of -h hostname
- dm_password: add Directory Manager auth
- root without dm_password: use autobind
- non-root without dm_password: use GSSAPI

In reality, I think all this service code always runs as root, so it may be a moot point, but this code is kinda convoluted.
Yep.
Here is updated patch.

--
/ Alexander Bokovoy
>From 81b1e0305ac8ad3516bb7bcaeb13999480e0f14f Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <aboko...@redhat.com>
Date: Fri, 13 Jul 2012 18:12:48 +0300
Subject: [PATCH 2/5] 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..65c8e1b87412fc6aba1187615e39c2ec523e00e5
 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 os.getegid() != 0:
+                auth_parms = ["-Y", "GSSAPI"]
 
-        args = ["/usr/bin/ldapmodify", "-h", hostname, "-v", "-f", path]
         args += auth_parms
 
         try:
-- 
1.7.10.4

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

Reply via email to