sdap.c revision 42604cc8d11743febf5aa892cb3a7d3c32bfed48
/*
SSSD
LDAP Helper routines
Copyright (C) Simo Sorce <ssorce@redhat.com>
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 "util/crypto/sss_crypto.h"
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_range.h"
/* =Retrieve-Options====================================================== */
struct sdap_attr_map *dst_map,
int entry_index)
{
return ENOMEM;
}
} else {
}
return EOK;
}
struct sdap_attr_map *src_map,
int num_entries,
struct sdap_attr_map **_map)
{
struct sdap_attr_map *map;
int i;
if (!map) {
return ENOMEM;
}
for (i = 0; i < num_entries; i++) {
return ENOMEM;
}
return ENOMEM;
}
} else {
}
}
/* Include the sentinel */
return EOK;
}
char *conf_attr,
char **_sysdb_attr,
char **_ldap_attr)
{
char *ldap_attr;
char *sysdb_attr;
char *sep;
} else {
return ERR_INVALID_EXTRA_ATTR;
}
}
return ENOMEM;
}
*_ldap_attr = ldap_attr;
return EOK;
}
int num_entries,
const char *sysdb_attr)
{
int i;
for (i = 0; i < num_entries; i++) {
return true;
}
}
return false;
}
struct sdap_attr_map *src_map,
char **extra_attrs,
struct sdap_attr_map **_map,
{
struct sdap_attr_map *map;
size_t i;
char *ldap_attr;
char *sysdb_attr;
if (extra_attrs == NULL) {
*_new_size = num_entries;
return EOK;
}
return ENOMEM;
}
for (i = 0; extra_attrs[i]; i++) {
continue;
}
"Attribute %s (%s in LDAP) is already used by SSSD, please "
return ERR_DUP_EXTRA_ATTR;
}
return ENOMEM;
}
}
/* Sentinel */
return EOK;
}
struct sdap_options *opts,
int extra_attr_index,
struct sdap_attr_map *src_map,
struct sdap_attr_map **_map,
{
const char *extra_attrs;
char **extra_attrs_list;
if (extra_attrs == NULL) {
*_new_size = num_entries;
return EOK;
}
/* split server parm into a list */
&extra_attrs_list, NULL);
return ret;
}
return ret;
}
return EOK;
}
static void sdap_inherit_basic_options(char **inherit_opt_list,
struct dp_option *parent_opts,
struct dp_option *subdom_opts)
{
int inherit_options[] = {
SDAP_OPTS_BASIC /* sentinel */
};
int i;
for (i = 0; inherit_options[i] != SDAP_OPTS_BASIC; i++) {
inherit_options[i],
}
}
static void sdap_inherit_user_options(char **inherit_opt_list,
struct sdap_attr_map *parent_user_map,
struct sdap_attr_map *child_user_map)
{
int inherit_options[] = {
SDAP_OPTS_USER /* sentinel */
};
int i;
int opt_index;
bool inherit_option;
for (i = 0; inherit_options[i] != SDAP_OPTS_USER; i++) {
opt_index = inherit_options[i];
false);
if (inherit_option == false) {
continue;
}
}
}
void sdap_inherit_options(char **inherit_opt_list,
struct sdap_options *parent_sdap_opts,
struct sdap_options *child_sdap_opts)
{
}
struct confdb_ctx *cdb,
const char *conf_path,
struct sdap_attr_map *def_map,
int num_entries,
struct sdap_attr_map **_map)
{
struct sdap_attr_map *map;
char *name;
int i, ret;
if (!map) {
return ENOMEM;
}
for (i = 0; i < num_entries; i++) {
&name);
return EINVAL;
}
if (name) {
"Could not sanitize attribute [%s]\n", name);
return EINVAL;
}
} else {
}
return EINVAL;
}
}
return EOK;
}
/* =Parse-msg============================================================= */
struct sysdb_attrs **_attrs,
bool disable_range_retrieval)
{
struct sysdb_attrs *attrs;
struct ldb_val v;
char *str;
int lerrno;
int base_attr_idx = 0;
const char *name;
bool store;
bool base64;
char *base_attr;
lerrno = 0;
if (ret != LDAP_OPT_SUCCESS) {
}
if (!attrs) {
goto done;
}
if (!str) {
goto done;
}
if (map) {
if (!vals) {
"Unknown entry type, no objectClasses found!\n");
goto done;
}
for (i = 0; vals[i]; i++) {
/* ok it's an entry of the right type */
break;
}
}
if (!vals[i]) {
goto done;
}
}
if (!str) {
"Entry has no attributes [%d(%s)]!?\n",
if (map) {
goto done;
}
}
while (str) {
base64 = false;
switch(ret) {
case EAGAIN:
/* This attribute contained range values and needs more to
* be retrieved
*/
/* TODO: return the set of attributes that need additional retrieval
* For now, we'll continue below and treat it as regular values.
*/
/* FALLTHROUGH */
case ECANCELED:
/* FALLTHROUGH */
case EOK:
break;
default:
"Could not determine if attribute [%s] was ranged\n", str);
goto done;
}
if (map) {
for (i = 1; i < attrs_num; i++) {
/* check if this attr is valid with the chosen schema */
/* check if it is an attr we are interested in */
}
/* interesting attr */
if (i < attrs_num) {
store = true;
base_attr_idx = i;
base64 = true;
}
} else {
store = false;
}
} else {
store = true;
}
store = false;
}
if (store) {
if (!vals) {
if (lerrno != LDAP_SUCCESS) {
goto done;
}
"Attribute [%s] has no values, skipping.\n", str);
} else {
if (!vals[0]) {
"Missing value after ldap_get_values() ??\n");
goto done;
}
for (i = 0; vals[i]; i++) {
"Value of attribute [%s] is empty. "
"Skipping this value.\n", str);
continue;
}
if (base64) {
if (!v.data) {
goto done;
}
} else {
}
if (map) {
/* The same LDAP attr might be used for more sysdb
* attrs in case there is a map. Find all that match
* and copy the value
*/
/* check if this attr is valid with the chosen
* schema */
/* check if it is an attr we are interested in */
&v);
if (ret) {
goto done;
}
}
}
} else {
/* No map, just store the attribute */
if (ret) {
goto done;
}
}
}
}
}
}
if (lerrno) {
goto done;
}
done:
return ret;
}
{
if (len == 0) {
}
return true;
}
return true;
}
return false;
}
/* Parses an LDAPDerefRes into sdap_deref_attrs structure */
struct sdap_attr_map_info *minfo,
struct sdap_deref_attrs ***_deref_res)
{
const char *orig_dn;
const char **ocs;
struct sdap_attr_map *map;
int num_attrs;
const char *name;
struct sdap_deref_attrs **res;
if (!res) {
goto done;
}
for (i=0; i < num_maps; i++) {
if (!res[i]) {
goto done;
}
}
goto done;
}
"Dereferenced DN: %s\n", orig_dn);
"Dereferenced entry [%s] has no attributes, skipping\n",
orig_dn);
*_deref_res = NULL;
goto done;
}
"No value for objectClass, skipping\n");
continue;
}
if (!ocs) {
goto done;
}
for (i=0; i<len; i++) {
if (!ocs[i]) {
goto done;
}
}
break;
}
}
if (!ocs) {
"Unknown entry type, no objectClasses found!\n");
goto done;
}
for (i=0; ocs[i]; i++) {
/* the objectclass is always the first name in the map */
"Found map for objectclass '%s'\n", ocs[i]);
break;
}
}
if (!map) continue;
goto done;
}
orig_dn);
if (ret) {
goto done;
}
for (a = 1; a < num_attrs; a++) {
/* check if this attr is valid with the chosen schema */
/* check if it is an attr we are interested in */
}
/* interesting attr */
if (a < num_attrs) {
} else {
continue;
}
"No value for attribute %s, skipping\n", name);
continue;
}
}
}
}
done:
return ret;
}
{
int ret;
const char *tls_opt;
if (tls_opt) {
}
}
}
}
}
else {
return EINVAL;
}
/* LDAP_OPT_X_TLS_REQUIRE_CERT has to be set as a global option,
if (ret != LDAP_OPT_SUCCESS) {
return EIO;
}
}
if (tls_opt) {
if (ret != LDAP_OPT_SUCCESS) {
return EIO;
}
}
if (tls_opt) {
if (ret != LDAP_OPT_SUCCESS) {
return EIO;
}
}
if (tls_opt) {
if (ret != LDAP_OPT_SUCCESS) {
return EIO;
}
}
if (tls_opt) {
if (ret != LDAP_OPT_SUCCESS) {
return EIO;
}
}
if (tls_opt) {
if (ret != LDAP_OPT_SUCCESS) {
return EIO;
}
}
return EOK;
}
{
int i;
if (!val) {
return false;
}
for (i = 0; i < l->num_vals; i++) {
continue;
}
return true;
}
return false;
}
{
int i;
return ENOMEM;
}
for (i = 0; i < num; i++) {
return ENOMEM;
}
}
return EOK;
}
struct sdap_handle *sh)
{
int ret;
int i;
if (ret) {
return ret;
}
if (ret) {
return ret;
}
if (ret) {
return ret;
}
}
}
return EOK;
}
struct ldb_message_element *el)
{
if (el->num_values == 0) {
}
} else {
}
return str;
}
struct sysdb_attrs *rootdse)
{
int i;
char *naming_context = NULL;
SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS) == 0) {
}
}
"No attributes [%s] or [%s] found in rootDSE.\n",
} else {
"Using value from [%s] as naming context.\n",
}
"Using value from [%s] as naming context.\n",
}
}
/* Some directory servers such as Novell eDirectory will return
* a zero-length namingContexts value in some situations. In this
* case, we should return it as NULL so things fail gracefully.
*/
}
return naming_context;
}
const char *unparsed_base,
int scope,
const char *filter,
struct sdap_search_base **_base)
{
struct sdap_search_base *base;
struct ldb_context *ldb;
if (!tmp_ctx) {
goto done;
}
/* Create a throwaway LDB context for validating the DN */
if (!ldb) {
goto done;
}
goto done;
}
goto done;
}
/* Validate the basedn */
if (!ldn) {
goto done;
}
if (!ldb_dn_validate(ldn)) {
goto done;
}
done:
return ret;
}
struct sdap_domain *sdom,
enum sdap_basic_opt class,
char *naming_context)
{
struct sdap_search_base ***bases;
switch(class) {
case SDAP_SEARCH_BASE:
break;
case SDAP_USER_SEARCH_BASE:
break;
case SDAP_GROUP_SEARCH_BASE:
break;
break;
case SDAP_SUDO_SEARCH_BASE:
break;
case SDAP_SERVICE_SEARCH_BASE:
break;
case SDAP_AUTOFS_SEARCH_BASE:
break;
default:
return EINVAL;
}
"Setting option [%s] to [%s].\n",
goto done;
}
done:
return ret;
}
struct sdap_options *opts,
struct sdap_domain *sdom)
{
int ret;
char *naming_context = NULL;
if (!sdom->search_bases
|| !sdom->user_search_bases
|| !sdom->group_search_bases
|| !sdom->sudo_search_bases
|| !sdom->autofs_search_bases) {
if (naming_context == NULL) {
/* This has to be non-fatal, since some servers offer
* multiple namingContexts entries. We will just
* add NULL checks for the search bases in the lookups.
*/
goto done;
}
}
/* Default */
if (!sdom->search_bases) {
}
/* Users */
if (!sdom->user_search_bases) {
}
/* Groups */
if (!sdom->group_search_bases) {
}
/* Netgroups */
if (!sdom->netgroup_search_bases) {
}
/* Sudo */
if (!sdom->sudo_search_bases) {
}
/* Services */
if (!sdom->service_search_bases) {
}
/* autofs */
if (!sdom->autofs_search_bases) {
}
done:
return ret;
}
const char *server,
struct sysdb_attrs *rootdse,
struct sdap_options *opts,
struct sdap_server_opts **srv_opts)
{
struct sdap_server_opts *so;
struct {
const char *last_name;
const char *entry_name;
{ SDAP_AD_LAST_USN, SDAP_AD_USN },
const char *last_usn_name;
const char *last_usn_value;
const char *entry_usn_name;
int ret;
int i;
if (!so) {
return ENOMEM;
}
return ENOMEM;
}
if (rootdse) {
if (last_usn_name) {
switch (ret) {
case ENOENT:
"%s configured but not found in rootdse!\n",
break;
case ERANGE:
"Multiple values of %s found in rootdse!\n",
break;
default:
"Unknown error (%d) checking rootdse!\n", ret);
}
} else {
if (!entry_usn_name) {
"%s found in rootdse but %s is not set!\n",
} else {
so->supports_usn = true;
"USN is not valid (value: %s)\n", last_usn_value);
} else {
}
}
}
} else {
/* no usn option configure, let's try to autodetect. */
/* Fixate discovered configuration */
so->supports_usn = true;
"USN is not valid (value: %s)\n", last_usn_value);
} else {
}
break;
}
}
}
/* Detect Active Directory version if available */
&dc_level);
/* Validate that the DC level matches an expected value */
switch(dc_level) {
case DS_BEHAVIOR_WIN2000:
case DS_BEHAVIOR_WIN2003:
case DS_BEHAVIOR_WIN2008:
case DS_BEHAVIOR_WIN2008R2:
case DS_BEHAVIOR_WIN2012:
case DS_BEHAVIOR_WIN2012R2:
"Setting AD compatibility level to [%d]\n",
break;
default:
"Received invalid value for AD compatibility level. "
"Using the lowest-common compatibility level\n");
}
"Error detecting Active Directory compatibility level "
"(%s). Continuing without AD performance enhancements\n",
}
}
if (!last_usn_name) {
"No known USN scheme is supported by this server!\n");
if (!entry_usn_name) {
"Will use modification timestamp as usn!\n");
}
}
}
}
}
if (opts->sudorule_map &&
}
return EOK;
}
struct sdap_server_opts **srv_opts)
{
return;
}
return;
}
/* discard if same as previous so we do not reset max usn values
* unnecessarily */
return;
}
}
{
int i;
if (filter) {
i = 0;
while (filter[i]) {
return true;
}
i++;
}
}
return false;
}
struct sdap_attr_map *map,
const char **filter,
const char ***_attrs,
{
const char **attrs;
int i, j;
/* Assume that all entries in the map have values */
if (!attrs) {
goto done;
}
/* first attribute is "objectclass" not the specifc one */
/* add the others */
for (i = j = 1; i < size; i++) {
j++;
}
}
/* Trim down the used memory if some attributes were NULL */
if (!attrs) {
goto done;
}
if (attr_count) *attr_count = j;
done:
return ret;
}
{
int ret;
if (ret != LDAP_SUCCESS) {
"sss_ldap_control_create failed [%d][%s].\n",
}
} else {
"Server does not support the requested control [%s].\n", oid);
}
return ret;
}
{
char *str;
struct ldb_message_element *el;
} else if (ret) {
return ret;
}
return EINVAL;
}
if (!str) {
return ENOMEM;
}
return EOK;
}
static errno_t
const char *attr_name,
struct sysdb_attrs *attrs,
struct sss_domain_info *dom,
const char **_primary_name)
{
char *name;
return EINVAL;
}
"Failed to format original name [%s]\n", orig_name);
return ENOMEM;
}
*_primary_name = name;
return EOK;
}
struct sdap_options *opts,
struct sysdb_attrs *attrs,
struct sss_domain_info *dom,
const char **_user_name)
{
return sdap_get_primary_name(memctx,
}
struct sdap_options *opts,
struct sysdb_attrs *attrs,
struct sss_domain_info *dom,
const char **_group_name)
{
return sdap_get_primary_name(memctx,
}
struct sdap_options *opts,
struct sysdb_attrs *attrs,
struct sss_domain_info *dom,
const char **_netgroup_name)
{
return sdap_get_primary_name(memctx,
}
{
} else {
return talloc_asprintf(mem_ctx,
"|(objectClass=%s)(objectClass=%s)",
}
}
struct sysdb_attrs *obj,
struct sss_domain_info *dom)
{
const char *original_dn = NULL;
if (ret) {
"The group has no original DN, assuming our domain\n");
return true;
}
"The group has no original DN, assuming our domain\n");
return true;
}
}
struct sysdb_attrs **dom_objects,
struct sss_domain_info *dom,
struct sysdb_attrs **all_objects,
bool filter)
{
/* Own objects from all_objects by dom_objects in case they belong
* to domain dom.
*
* Don't copy objects from other domains in case
* the search was for parent domain but a child domain would match,
* too, such as:
* dc=example,dc=com
* dc=child,dc=example,dc=com
* while searching for an object from dc=example.
*/
if (filter &&
continue;
}
copied++;
}
return copied;
}