This patch introduces the first set of native ipa options.
At the moment a full configuration still requires specifying krb5
specific options. This will be fixed once Sumit provides a patch for the
krb5 provider that uses the dp_option helpers.

NOTE: this is not reflected in the man page which is built with the
final result in mind.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
>From 9b8d75f040debbafa83b7eb15157e6b3f14dbe84 Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Fri, 16 Oct 2009 18:38:40 -0400
Subject: [PATCH] Start implementing ipa specific options.

First step generate ldap options from ipa options.
Add sssd-ipa man page too.
---
 server/Makefile.am                    |    4 +-
 server/man/sssd-ipa.5.xml             |  182 +++++++++++++++++++
 server/providers/data_provider.h      |   18 ++
 server/providers/data_provider_opts.c |  179 ++++++++++++++++++-
 server/providers/ipa/ipa_common.c     |  319 +++++++++++++++++++++++++++++++++
 server/providers/ipa/ipa_common.h     |   61 +++++++
 server/providers/ipa/ipa_init.c       |   23 ++-
 7 files changed, 778 insertions(+), 8 deletions(-)
 create mode 100644 server/man/sssd-ipa.5.xml
 create mode 100644 server/providers/ipa/ipa_common.c
 create mode 100644 server/providers/ipa/ipa_common.h

diff --git a/server/Makefile.am b/server/Makefile.am
index 88d2208..81f438d 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -265,6 +265,7 @@ dist_noinst_HEADERS = \
     providers/ldap/ldap_common.h \
     providers/ldap/sdap.h \
     providers/ldap/sdap_async.h \
+    providers/ipa/ipa_common.h \
     tools/tools_util.h \
     tools/sss_sync_ops.h \
     resolv/async_resolv.h \
@@ -472,6 +473,7 @@ libsss_krb5_la_LDFLAGS = \
 
 libsss_ipa_la_SOURCES = \
 	providers/ipa/ipa_init.c \
+	providers/ipa/ipa_common.c \
     providers/ldap/ldap_id.c \
     providers/ldap/ldap_auth.c \
     providers/ldap/ldap_common.c \
@@ -552,7 +554,7 @@ XSLTPROC_FLAGS = --catalogs --xinclude --nonet
 dist_man_MANS = man/sss_useradd.8 man/sss_userdel.8 man/sss_usermod.8 \
 		man/sss_groupadd.8 man/sss_groupdel.8 man/sss_groupmod.8 \
 		man/sssd.8 man/sssd.conf.5 man/sssd-ldap.5 man/sssd-krb5.5 \
-		man/sssd_krb5_locator_plugin.8
+		man/sssd-ipa.5 man/sssd_krb5_locator_plugin.8
 
 SUFFIXES = .1.xml .1 .3.xml .3 .5.xml .5 .8.xml .8
 .1.xml.1:
diff --git a/server/man/sssd-ipa.5.xml b/server/man/sssd-ipa.5.xml
new file mode 100644
index 0000000..c5c96d1
--- /dev/null
+++ b/server/man/sssd-ipa.5.xml
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd";>
+<reference>
+<title>SSSD Manual pages</title>
+<refentry>
+    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; href="include/upstream.xml" />
+
+    <refmeta>
+        <refentrytitle>sssd-ipa</refentrytitle>
+        <manvolnum>5</manvolnum>
+        <refmiscinfo class="manual">File Formats and Conventions</refmiscinfo>
+    </refmeta>
+
+    <refnamediv id='name'>
+        <refname>sssd-ipa</refname>
+        <refpurpose>the configuration file for SSSD</refpurpose>
+    </refnamediv>
+
+    <refsect1 id='description'>
+        <title>DESCRIPTION</title>
+        <para>
+            This manual page describes the configuration of the IPA Provider
+            for
+            <citerefentry>
+                <refentrytitle>sssd</refentrytitle>
+                <manvolnum>8</manvolnum>
+            </citerefentry>.
+            For a detailed syntax reference, please refer to the <quote>FILE FORMAT</quote> section of the
+            <citerefentry>
+                <refentrytitle>sssd.conf</refentrytitle>
+                <manvolnum>5</manvolnum>
+            </citerefentry> manual page
+        </para>
+        <para>
+            The IPA provider is a backend useful to connect to an IPA server.
+            (see freeipa.org for information about IPa servers).
+            It requires that the machine has been joined to the IPA domain,
+            and configuration is almost entirely self discovered and obtained
+            directly from the server.
+        </para>
+
+    </refsect1>
+
+    <refsect1 id='file-format'>
+        <title>CONFIGURATION OPTIONS</title>
+        <para>
+            <citerefentry>
+                <refentrytitle>sssd.conf</refentrytitle>
+                <manvolnum>5</manvolnum>
+            </citerefentry> manual page, section <quote>DOMAIN SECTIONS</quote>
+            for details on the configuration of a SSSD domain.
+            <variablelist>
+                <varlistentry>
+                    <term>ipa_domain (string)</term>
+                    <listitem>
+                        <para>
+                            Specifies the name of the IPA domain.
+                            This is optional, if not provided the configuration
+                            domain name is used.
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ipa_server (string)</term>
+                    <listitem>
+                        <para>
+                            The name of the IPA server.
+                            If autodiscovery is enabled this is optional.
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ipa_hostname (string)</term>
+                    <listitem>
+                        <para>
+                            Optional. Maybe set on some machine where the
+                            hostname(5) does not reflect the fully qualified
+                            name used in the IPA domain to identify this host.
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>krb5_ccachedir (string)</term>
+                    <listitem>
+                        <para>
+                            Directory to store credential caches.
+                        </para>
+                        <para>
+                            Default: /tmp
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ipa_search_timeout (integer)</term>
+                    <listitem>
+                        <para>
+                            Specifies the timeout (in seconds) after which
+                            a search against the ipa server is forcibly
+                            terminated.
+                        </para>
+                        <para>
+                            Default: 60
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ipa_network_timeout (integer)</term>
+                    <listitem>
+                        <para>
+                            Specifies the timeout (in seconds) after which
+                            the
+                            <citerefentry>
+                                <refentrytitle>poll</refentrytitle>
+                                <manvolnum>2</manvolnum>
+                            </citerefentry>/<citerefentry>
+                                <refentrytitle>select</refentrytitle>
+                                <manvolnum>2</manvolnum>
+                            </citerefentry>
+                            following a non-search operation against the ipa
+                            server is forcibly terminated.
+                        </para>
+                        <para>
+                            Default: 6
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ipa_offline_timeout (integer)</term>
+                    <listitem>
+                        <para>
+                            Specifies the "black-out" time before any new
+                            network operation is attempted after the ipa
+                            provider has turned into offline operation mode.
+                        </para>
+                        <para>
+                            Default: 60
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+            </variablelist>
+        </para>
+    </refsect1>
+
+    <refsect1 id='example'>
+        <title>EXAMPLE</title>
+        <para>
+            The following example assumes that SSSD is correctly
+            configured and example.com is one of the domains in the
+            <replaceable>[sssd]</replaceable> section. This examples shows only
+            the ipa provider specific options.
+        </para>
+        <para>
+<programlisting>
+    [domain/example.com]
+    id_provider = ipa
+    ipa_server = ipaserver.example.com
+    ipa_hostname = myhost.example.com
+</programlisting>
+        </para>
+    </refsect1>
+
+    <refsect1 id='see_also'>
+        <title>SEE ALSO</title>
+        <para>
+            <citerefentry>
+                <refentrytitle>sssd.conf</refentrytitle><manvolnum>5</manvolnum>
+            </citerefentry>,
+            <citerefentry>
+                <refentrytitle>sssd</refentrytitle><manvolnum>8</manvolnum>
+            </citerefentry>
+        </para>
+    </refsect1>
+</refentry>
+</reference>
diff --git a/server/providers/data_provider.h b/server/providers/data_provider.h
index 7653f07..57b318f 100644
--- a/server/providers/data_provider.h
+++ b/server/providers/data_provider.h
@@ -180,6 +180,11 @@ int dp_get_options(TALLOC_CTX *memctx,
                    int num_opts,
                    struct dp_option **_opts);
 
+int dp_copy_options(TALLOC_CTX *memctx,
+                    struct dp_option *src_opts,
+                    int num_opts,
+                    struct dp_option **_opts);
+
 const char *_dp_opt_get_cstring(struct dp_option *opts,
                                     int id, const char *location);
 char *_dp_opt_get_string(struct dp_option *opts,
@@ -196,4 +201,17 @@ bool _dp_opt_get_bool(struct dp_option *opts,
 #define dp_opt_get_int(o, i) _dp_opt_get_int(o, i, __FUNCTION__)
 #define dp_opt_get_bool(o, i) _dp_opt_get_bool(o, i, __FUNCTION__)
 
+int _dp_opt_set_string(struct dp_option *opts, int id,
+                       const char *s, const char *location);
+int _dp_opt_set_blob(struct dp_option *opts, int id,
+                     struct dp_opt_blob b, const char *location);
+int _dp_opt_set_int(struct dp_option *opts, int id,
+                    int i, const char *location);
+int _dp_opt_set_bool(struct dp_option *opts, int id,
+                     bool b, const char *location);
+#define dp_opt_set_string(o, i, v) _dp_opt_set_string(o, i, v, __FUNCTION__)
+#define dp_opt_set_blob(o, i, v) _dp_opt_set_blob(o, i, v, __FUNCTION__)
+#define dp_opt_set_int(o, i, v) _dp_opt_set_int(o, i, v, __FUNCTION__)
+#define dp_opt_set_bool(o, i, v) _dp_opt_set_bool(o, i, v, __FUNCTION__)
+
 #endif /* __DATA_PROVIDER_ */
diff --git a/server/providers/data_provider_opts.c b/server/providers/data_provider_opts.c
index 581b928..98283e4 100644
--- a/server/providers/data_provider_opts.c
+++ b/server/providers/data_provider_opts.c
@@ -33,7 +33,7 @@ int dp_get_options(TALLOC_CTX *memctx,
     struct dp_option *opts;
     int i, ret;
 
-    opts = talloc_array(memctx, struct dp_option, num_opts);
+    opts = talloc_zero_array(memctx, struct dp_option, num_opts);
     if (!opts) return ENOMEM;
 
     for (i = 0; i < num_opts; i++) {
@@ -80,7 +80,7 @@ int dp_get_options(TALLOC_CTX *memctx,
                 opts[i].val.blob.length = 0;
             }
 
-            DEBUG(6, ("Option %s has %s value\n",
+            DEBUG(6, ("Option %s has %s binary value.\n",
                       opts[i].opt_name,
                       opts[i].val.blob.length?"a":"no"));
             break;
@@ -126,6 +126,95 @@ done:
 
 /* =Basic-Option-Helpers================================================== */
 
+int dp_copy_options(TALLOC_CTX *memctx,
+                    struct dp_option *src_opts,
+                    int num_opts,
+                    struct dp_option **_opts)
+{
+    struct dp_option *opts;
+    int i, ret;
+
+    opts = talloc_zero_array(memctx, struct dp_option, num_opts);
+    if (!opts) return ENOMEM;
+
+    for (i = 0; i < num_opts; i++) {
+        opts[i].opt_name = src_opts[i].opt_name;
+        opts[i].type = src_opts[i].type;
+        opts[i].def_val = src_opts[i].def_val;
+        ret = EOK;
+
+        switch (src_opts[i].type) {
+        case DP_OPT_STRING:
+            if (src_opts[i].val.string) {
+                ret = dp_opt_set_string(opts, i, src_opts[i].val.string);
+            } else if (src_opts[i].def_val.string) {
+                ret = dp_opt_set_string(opts, i, src_opts[i].def_val.string);
+            }
+            if (ret != EOK) {
+                DEBUG(0, ("Failed to copy value for option (%s)\n",
+                          opts[i].opt_name));
+                goto done;
+            }
+            DEBUG(6, ("Option %s has value %s\n",
+                  opts[i].opt_name, opts[i].val.cstring));
+            break;
+
+        case DP_OPT_BLOB:
+            if (src_opts[i].val.blob.data) {
+                ret = dp_opt_set_blob(opts, i, src_opts[i].val.blob);
+            } else if (src_opts[i].def_val.blob.data) {
+                ret = dp_opt_set_blob(opts, i, src_opts[i].def_val.blob);
+            }
+            if (ret != EOK) {
+                DEBUG(0, ("Failed to retrieve value for option (%s)\n",
+                          opts[i].opt_name));
+                goto done;
+            }
+            DEBUG(6, ("Option %s has %s binary value.\n",
+                      opts[i].opt_name,
+                      opts[i].val.blob.length?"a":"no"));
+            break;
+
+        case DP_OPT_NUMBER:
+            if (src_opts[i].val.number) {
+                ret = dp_opt_set_int(opts, i, src_opts[i].val.number);
+            } else if (src_opts[i].def_val.number) {
+                ret = dp_opt_set_int(opts, i, src_opts[i].def_val.number);
+            }
+            if (ret != EOK) {
+                DEBUG(0, ("Failed to retrieve value for option (%s)\n",
+                          opts[i].opt_name));
+                goto done;
+            }
+            DEBUG(6, ("Option %s has value %d\n",
+                  opts[i].opt_name, opts[i].val.number));
+            break;
+
+        case DP_OPT_BOOL:
+            if (src_opts[i].val.boolean) {
+                ret = dp_opt_set_bool(opts, i, src_opts[i].val.boolean);
+            } else if (src_opts[i].def_val.boolean) {
+                ret = dp_opt_set_int(opts, i, src_opts[i].def_val.boolean);
+            }
+            if (ret != EOK) {
+                DEBUG(0, ("Failed to retrieve value for option (%s)\n",
+                          opts[i].opt_name));
+                goto done;
+            }
+            DEBUG(6, ("Option %s is %s\n",
+                      opts[i].opt_name,
+                      opts[i].val.boolean?"TRUE":"FALSE"));
+            break;
+        }
+    }
+
+    *_opts = opts;
+
+done:
+    if (ret != EOK) talloc_zfree(opts);
+    return ret;
+}
+
 static const char *dp_opt_type_to_string(enum dp_opt_type type)
 {
     switch (type) {
@@ -141,6 +230,7 @@ static const char *dp_opt_type_to_string(enum dp_opt_type type)
     return NULL;
 }
 
+/* Getters */
 const char *_dp_opt_get_cstring(struct dp_option *opts,
                                 int id, const char *location)
 {
@@ -207,3 +297,88 @@ bool _dp_opt_get_bool(struct dp_option *opts,
     return opts[id].val.boolean;
 }
 
+/* Setters */
+int _dp_opt_set_string(struct dp_option *opts, int id,
+                       const char *s, const char *location)
+{
+    if (opts[id].type != DP_OPT_STRING) {
+        DEBUG(0, ("[%s] Requested type 'String' for option '%s'"
+                  " but type is '%s'!\n",
+                  location, opts[id].opt_name,
+                  dp_opt_type_to_string(opts[id].type)));
+        return EINVAL;
+    }
+
+    if (opts[id].val.string) {
+        talloc_zfree(opts[id].val.string);
+    }
+    if (s) {
+        opts[id].val.string = talloc_strdup(opts, s);
+        if (!opts[id].val.string) {
+            DEBUG(0, ("talloc_strdup() failed!\n"));
+            return ENOMEM;
+        }
+    }
+
+    return EOK;
+}
+
+int _dp_opt_set_blob(struct dp_option *opts, int id,
+                     struct dp_opt_blob b, const char *location)
+{
+    if (opts[id].type != DP_OPT_BLOB) {
+        DEBUG(0, ("[%s] Requested type 'Blob' for option '%s'"
+                  " but type is '%s'!\n",
+                  location, opts[id].opt_name,
+                  dp_opt_type_to_string(opts[id].type)));
+        return EINVAL;
+    }
+
+    if (opts[id].val.blob.data) {
+        talloc_zfree(opts[id].val.blob.data);
+        opts[id].val.blob.length = 0;
+    }
+    if (b.data) {
+        opts[id].val.blob.data = talloc_memdup(opts, b.data, b.length);
+        if (!opts[id].val.blob.data) {
+            DEBUG(0, ("talloc_memdup() failed!\n"));
+            return ENOMEM;
+        }
+    }
+    opts[id].val.blob.length = b.length;
+
+    return EOK;
+}
+
+int _dp_opt_set_int(struct dp_option *opts, int id,
+                    int i, const char *location)
+{
+    if (opts[id].type != DP_OPT_NUMBER) {
+        DEBUG(0, ("[%s] Requested type 'Number' for option '%s'"
+                  " but type is '%s'!\n",
+                  location, opts[id].opt_name,
+                  dp_opt_type_to_string(opts[id].type)));
+        return EINVAL;
+    }
+
+    opts[id].val.number = i;
+
+    return EOK;
+}
+
+int _dp_opt_set_bool(struct dp_option *opts, int id,
+                     bool b, const char *location)
+{
+    if (opts[id].type != DP_OPT_BOOL) {
+        DEBUG(0, ("[%s] Requested type 'Boolean' for option '%s'"
+                  " but type is '%s'!\n",
+                  location, opts[id].opt_name,
+                  dp_opt_type_to_string(opts[id].type)));
+        return EINVAL;
+    }
+
+    opts[id].val.boolean = b;
+
+    return EOK;
+}
+
diff --git a/server/providers/ipa/ipa_common.c b/server/providers/ipa/ipa_common.c
new file mode 100644
index 0000000..799ac2f
--- /dev/null
+++ b/server/providers/ipa/ipa_common.c
@@ -0,0 +1,319 @@
+/*
+    SSSD
+
+    IPA Provider Common Functions
+
+    Authors:
+        Simo Sorce <sso...@redhat.com>
+
+    Copyright (C) 2009 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ctype.h>
+#include "providers/ipa/ipa_common.h"
+
+struct dp_option ipa_basic_opts[] = {
+    { "ipa_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ipa_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ipa_hostname", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ipa_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
+    { "ipa_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+    { "ipa_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+    { "ipa_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
+    { "ipa_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER },
+    { "ipa_stale_time", DP_OPT_NUMBER, { .number = 1800 }, NULL_NUMBER },
+};
+
+struct dp_option ipa_def_ldap_opts[] = {
+    { "ldap_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_default_authtok_type", DP_OPT_STRING, NULL_STRING, NULL_STRING},
+    { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },
+    { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
+    { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+    { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
+    { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING },
+    { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },
+    { "ldap_user_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },
+    { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_schema", DP_OPT_STRING, { "ipa_v1" }, NULL_STRING },
+    { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
+    { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+    { "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER },
+    { "ldap_stale_time", DP_OPT_NUMBER, { .number = 1800 }, NULL_NUMBER },
+    { "ldap_tls_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_tls_cacertdir", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_id_use_start_tls", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+    { "ldap_sasl_mech", DP_OPT_STRING, { "GSSAPI" } , NULL_STRING },
+    { "ldap_sasl_authid", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_krb5_keytab", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
+    /* use the same parm name as the krb5 module so we set it only once */
+    { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }
+};
+
+struct sdap_id_map ipa_user_map[] = {
+    { "ldap_user_object_class", "posixAccount", SYSDB_USER_CLASS, NULL },
+    { "ldap_user_name", "uid", SYSDB_NAME, NULL },
+    { "ldap_user_pwd", "userPassword", SYSDB_PWD, NULL },
+    { "ldap_user_uid_number", "uidNumber", SYSDB_UIDNUM, NULL },
+    { "ldap_user_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+    { "ldap_user_gecos", "gecos", SYSDB_GECOS, NULL },
+    { "ldap_user_home_directory", "homeDirectory", SYSDB_HOMEDIR, NULL },
+    { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL },
+    { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL },
+    { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL },
+    { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL },
+    { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL },
+    { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL },
+    { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL },
+    { "ldap_user_shadow_min", "shadowMin", SYSDB_SHADOWPW_MIN, NULL },
+    { "ldap_user_shadow_max", "shadowMax", SYSDB_SHADOWPW_MAX, NULL },
+    { "ldap_user_shadow_warning", "shadowWarning", SYSDB_SHADOWPW_WARNING, NULL },
+    { "ldap_user_shadow_inactive", "shadowInactive", SYSDB_SHADOWPW_INACTIVE, NULL },
+    { "ldap_user_shadow_expire", "shadowExpire", SYSDB_SHADOWPW_EXPIRE, NULL },
+    { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL },
+    { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL },
+    { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL },
+    { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL }
+};
+
+struct sdap_id_map ipa_group_map[] = {
+    { "ldap_group_object_class", "posixGroup", SYSDB_GROUP_CLASS, NULL },
+    { "ldap_group_name", "cn", SYSDB_NAME, NULL },
+    { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL },
+    { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
+    { "ldap_group_member", "member", SYSDB_MEMBER, NULL },
+    { "ldap_group_uuid", "nsUniqueId", SYSDB_UUID, NULL },
+    { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }
+};
+
+int domain_to_basedn(TALLOC_CTX *memctx, const char *domain, char **basedn)
+{
+    const char *s;
+    char *dn;
+    char *p;
+    int l;
+
+    s = domain;
+    dn = talloc_strdup(memctx, "dc=");
+
+    while ((p = strchr(s, '.'))) {
+        l = p - s;
+        dn = talloc_asprintf_append_buffer(dn, "%.*s,dc=", l, s);
+        if (!dn) {
+            return ENOMEM;
+        }
+        s = p + 1;
+    }
+    dn = talloc_strdup_append_buffer(dn, s);
+    if (!dn) {
+        return ENOMEM;
+    }
+
+    *basedn = dn;
+    return EOK;
+}
+
+int ipa_get_options(TALLOC_CTX *memctx,
+                    struct confdb_ctx *cdb,
+                    const char *conf_path,
+                    struct sss_domain_info *dom,
+                    struct ipa_options **_opts)
+{
+    struct ipa_options *opts;
+    char *domain;
+    char *server;
+    int ret;
+
+    opts = talloc_zero(memctx, struct ipa_options);
+    if (!opts) return ENOMEM;
+
+    ret = dp_get_options(opts, cdb, conf_path,
+                         ipa_basic_opts,
+                         IPA_OPTS_BASIC,
+                         &opts->basic);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    domain = dp_opt_get_string(opts->basic, IPA_DOMAIN);
+    if (!domain) {
+        ret = dp_opt_set_string(opts->basic, IPA_DOMAIN, dom->name);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    /* FIXME: Make non-fatal once we have discovery */
+    server = dp_opt_get_string(opts->basic, IPA_SERVER);
+    if (!server) {
+        DEBUG(0, ("Can't find ipa server, missing option!\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = EOK;
+    *_opts = opts;
+
+done:
+    if (ret != EOK) {
+        talloc_zfree(opts);
+    }
+    return ret;
+}
+
+/* the following preprocessor code is used to keep track of
+ * the options in the ldap module, so that if they change and ipa
+ * is not updated correspondingly this will trigger a build error */
+#if SDAP_OPTS_BASIC > 27
+#error There are ldap options not accounted for
+#endif
+
+int ipa_get_id_options(TALLOC_CTX *memctx,
+                       struct confdb_ctx *cdb,
+                       const char *conf_path,
+                       struct ipa_options *ipa_opts,
+                       struct sdap_options **_opts)
+{
+    TALLOC_CTX *tmpctx;
+    char *hostname;
+    char *basedn;
+    char *realm;
+    char *value;
+    int ret;
+    int i;
+
+    tmpctx = talloc_new(memctx);
+    if (!tmpctx) {
+        return ENOMEM;
+    }
+
+    ipa_opts->id = talloc_zero(memctx, struct sdap_options);
+    if (!ipa_opts->id) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* generate sdap options */
+    ret = dp_copy_options(ipa_opts, ipa_def_ldap_opts,
+                          SDAP_OPTS_BASIC, &ipa_opts->id->basic);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* set ldap_uri */
+    value = talloc_asprintf(tmpctx, "ldap://%s";,
+                            dp_opt_get_string(ipa_opts->basic, IPA_SERVER));
+    if (!value) {
+        ret = ENOMEM;
+        goto done;
+    }
+    ret = dp_opt_set_string(ipa_opts->id->basic, SDAP_URI, value);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = domain_to_basedn(tmpctx,
+                           dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN),
+                           &basedn);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* FIXME: get values by querying IPA */
+    /* set ldap_user_search_base */
+    value = talloc_asprintf(tmpctx, "cn=users,cn=accounts,%s", basedn);
+    if (!value) {
+        ret = ENOMEM;
+        goto done;
+    }
+    ret = dp_opt_set_string(ipa_opts->id->basic,
+                            SDAP_USER_SEARCH_BASE, value);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* set ldap_group_search_base */
+    value = talloc_asprintf(tmpctx, "cn=groups,cn=accounts,%s", basedn);
+    if (!value) {
+        ret = ENOMEM;
+        goto done;
+    }
+    ret = dp_opt_set_string(ipa_opts->id->basic,
+                            SDAP_GROUP_SEARCH_BASE, value);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* set the ldap_sasl_authid if the ipa_hostname override was specified */
+    hostname = dp_opt_get_string(ipa_opts->basic, IPA_HOSTNAME);
+    if (hostname) {
+        value = talloc_asprintf(tmpctx, "host/%s", hostname);
+        if (!value) {
+            ret = ENOMEM;
+            goto done;
+        }
+        ret = dp_opt_set_string(ipa_opts->id->basic,
+                                SDAP_SASL_AUTHID, value);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    /* set krb realm */
+    realm = dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN);
+    for (i = 0; realm[i]; i++) {
+        realm[i] = toupper(realm[i]);
+    }
+    ret = dp_opt_set_string(ipa_opts->id->basic,
+                            SDAP_KRB5_REALM, realm);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sdap_get_map(ipa_opts->id,
+                       cdb, conf_path,
+                       ipa_user_map,
+                       SDAP_OPTS_USER,
+                       &ipa_opts->id->user_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sdap_get_map(ipa_opts->id,
+                       cdb, conf_path,
+                       ipa_group_map,
+                       SDAP_OPTS_GROUP,
+                       &ipa_opts->id->group_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = EOK;
+    *_opts = ipa_opts->id;
+
+done:
+    talloc_zfree(tmpctx);
+    if (ret != EOK) {
+        talloc_zfree(ipa_opts->id);
+    }
+    return ret;
+}
+
diff --git a/server/providers/ipa/ipa_common.h b/server/providers/ipa/ipa_common.h
new file mode 100644
index 0000000..80f5294
--- /dev/null
+++ b/server/providers/ipa/ipa_common.h
@@ -0,0 +1,61 @@
+/*
+    SSSD
+
+    IPA Common utility code
+
+    Copyright (C) Simo Sorce <sso...@redhat.com> 2009
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _IPA_COMMON_H_
+#define _IPA_COMMON_H_
+
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "providers/ldap/ldap_common.h"
+
+enum ipa_basic_opt {
+    IPA_DOMAIN = 0,
+    IPA_SERVER,
+    IPA_HOSTNAME,
+    IPA_SEARCH_TIMEOUT,
+    IPA_NETWORK_TIMEOUT,
+    IPA_OPT_TIMEOUT,
+    IPA_OFFLINE_TIMEOUT,
+    IPA_ENUM_REFRESH_TIMEOUT,
+    IPA_STALE_TIME,
+
+    IPA_OPTS_BASIC /* opts counter */
+};
+
+struct ipa_options {
+    struct dp_option *basic;
+    struct sdap_options *id;
+};
+
+/* options parsers */
+int ipa_get_options(TALLOC_CTX *memctx,
+                    struct confdb_ctx *cdb,
+                    const char *conf_path,
+                    struct sss_domain_info *dom,
+                    struct ipa_options **_opts);
+
+int ipa_get_id_options(TALLOC_CTX *memctx,
+                       struct confdb_ctx *cdb,
+                       const char *conf_path,
+                       struct ipa_options *ipa_opts,
+                       struct sdap_options **_opts);
+
+#endif /* _IPA_COMMON_H_ */
diff --git a/server/providers/ipa/ipa_init.c b/server/providers/ipa/ipa_init.c
index ebbeec4..9cdcf4b 100644
--- a/server/providers/ipa/ipa_init.c
+++ b/server/providers/ipa/ipa_init.c
@@ -25,9 +25,11 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/stat.h>
-#include "providers/ldap/ldap_common.h"
+#include "providers/ipa/ipa_common.h"
 #include "providers/krb5/krb5_auth.h"
 
+struct ipa_options *ipa_options = NULL;
+
 /* Id Handler */
 struct bet_ops ipa_id_ops = {
     .handler = sdap_account_info_handler,
@@ -51,13 +53,24 @@ int sssm_ipa_init(struct be_ctx *bectx,
     struct sdap_id_ctx *ctx;
     int ret;
 
-    ctx = talloc_zero(bectx, struct sdap_id_ctx);
-    if (!ctx) return ENOMEM;
+    if (!ipa_options) {
+        ipa_get_options(bectx, bectx->cdb,
+                        bectx->conf_path,
+                        bectx->domain, &ipa_options);
+    }
+    if (!ipa_options) {
+        return ENOMEM;
+    }
 
+    ctx = talloc_zero(bectx, struct sdap_id_ctx);
+    if (!ctx) {
+        return ENOMEM;
+    }
     ctx->be = bectx;
 
-    ret = ldap_get_options(ctx, bectx->cdb,
-                           bectx->conf_path, &ctx->opts);
+    ret = ipa_get_id_options(ctx, bectx->cdb,
+                             bectx->conf_path,
+                             ipa_options, &ctx->opts);
     if (ret != EOK) {
         goto done;
     }
-- 
1.6.2.5

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to