Skip to content
Commits on Source (13)
  • stlaz's avatar
    Update README · 71ca6132
    stlaz authored
    
    
    Replacing the old link pointing to fedorahosted.org retirement page.
    
    Signed-off-by: default avatarStanislav Laznicka <slaznick@redhat.com>
    71ca6132
  • Alexander Bokovoy's avatar
    Update spec file to Fedora version · 1020e4ec
    Alexander Bokovoy authored
    1020e4ec
  • Alexander Bokovoy's avatar
    aab5d0f0
  • Alexander Bokovoy's avatar
    Add dummy handler for a related add/delete/modify to NIS plugin · d0189d78
    Alexander Bokovoy authored
    NIS doesn't need to handle ID overrides, it has to always skip related entries
    d0189d78
  • Alexander Bokovoy's avatar
    track changes to ID overrides and evict map cache entries · e83cdaa4
    Alexander Bokovoy authored
    Plug into a processing of LDAP add/delete/modify to see if an ID override entry
    was added/deleted/updated. ID overrides aren't directly used to produce
    map cache entries but when AD user or group is resolved, SSSD on IPA
    master amends that information with ID Override from a Default Trust
    View. Since nothing else would remove AD user or group entry from the map cache
    on ID override change, handle their removal here.
    
    Check if we have any nssswitch-generated entry in a map cache that
    corresponds to this entry. Such entries would be evicted from the map
    cache to allow their refresh.
    
    Allow backends to inspect entries related to a map set
    
    Entries may be related to a map set content but not used directly to
    generate it. An example would be ID overrides in FreeIPA. An addition,
    removal or change of an ID override in the Default Trust View should be
    reflected by evicting an entry from the corresponding seti.
    
    Let backends to handle exact logic. NIS backend does not support
    exposing AD users so it provides set of dummy callbacks that always
    return FALSE (entry is not related). Schema Compat backend, on other
    hand, does track ID overrides in a Default Trust View in FreeIPA.
    e83cdaa4
  • Alexander Bokovoy's avatar
    configure.ac: detect extended NSS API provided by SSSD · 9481aa38
    Alexander Bokovoy authored
    SSSD exposes an extended NSS API via libsss_nss_idmap. This API allows
    to query getpwnam()/getgrnam()/getgruid()/getpwuid()/getgrouplist()
    information with a timeout per request. As result, an application has
    possibility to cancel too long request.
    
    This API also allows to ignore SSSD cache or invalidate it when
    requesting certain information. slapi-nis needs this functionality when
    invalidating own entries as result of changes done by other LDAP clients
    in the areas which slapi-nis doesn't track directly.
    
    For example, an update of ID override in the Default Trust View should
    invalidate user or group entry for that AD object. Since retrieval of
    the user/group information relies on SSSD, SSSD needs to be notified
    that there is a change in ID override and evict the entry from its cache
    as well.
    9481aa38
  • Alexander Bokovoy's avatar
    schema-compat: add support for timeout-based NSS queries with libsss_nss_idmap · 9cbb660d
    Alexander Bokovoy authored
    In case libsss_nss_idmap provides timeout-enabled NSS API, use it.
    This solves a problem of too long queries to an NSS backend with
    traditional POSIX NSS API. In case SSSD takes too long to respond
    to a query, corresponding 389-ds thread running schema-compat plugin
    would stuck waiting that response. It can lead to an exhaustion of
    389-ds threads.
    
    A refactored interface to NSS backends is introduced with this commit.
    A backend API looks like an API an NSS plugin has to implement in glibc
    but also allows to handle timeout-based requests internally.
    
    If backend implements timeout-enabled calls, then
    backend_nss_set_timeout() function can be used to modify a per-context
    state. There is no need for a caller to know whether backend supports
    timeout-enabled calls because either way these calls are synchronous
    and backend choice is done at compile-time.
    
    schema-compat plugin uses 10 seconds as its default timeout. One can
    change it via 'slapi-nss-timeout' attribute in the plugin config entry.
    9cbb660d
  • Alexander Bokovoy's avatar
    back-sch: cancel memberof retrieval in case of a dirsrv shutdown · f11619d5
    Alexander Bokovoy authored
    Do not wait for SSSD to become online if directory server is going
    for shutdown. Since it is guaranteed that SSSD will not be able to
    function with 389-ds offline, it makes no sense to continue a loop.
    f11619d5
  • Alexander Bokovoy's avatar
    Fix nss_sss callers · fc259fa6
    Alexander Bokovoy authored
    fc259fa6
  • Alexander Bokovoy's avatar
    Clean up unused code · b8aece71
    Alexander Bokovoy authored
    b8aece71
  • Alexander Bokovoy's avatar
    Synchronize nsswitch backend code with freeIPA · 1229089c
    Alexander Bokovoy authored
    FreeIPA ipa-extdom-extop plugin uses the same logic as slapi-nis
    schema-compat plugin to handle requests to SSSD. Thus, we keep the
    code synchronized across both code bases. Since both plugins are loaded
    into the same address space we currently rename functions to allow them
    to co-exist. In future we'd move some of common code to a shared
    library.
    1229089c
  • Alexander Bokovoy's avatar
    Use extended SSSD API to signal that an entry should not be cached anymore · 4cd8ef26
    Alexander Bokovoy authored
    When ID override is changed, we remove affected entry from the schema
    compat subtrees. However, we should also signal to SSSD that ID override
    did change and thus SSSD should stop caching the entry. As result, next
    look up of the affected entry should cause a refresh of the data in
    SSSD.
    
    This is important for cases when group membership changes for AD users.
    4cd8ef26
  • Alexander Bokovoy's avatar
    Release 0.56.2 · 1ce22281
    Alexander Bokovoy authored
    1ce22281
......@@ -10,4 +10,4 @@ alternate view of entries stored in part of the DIT, optionally adding,
dropping, or renaming attribute values, and optionally retrieving values
for attributes from multiple entries in the tree.
This project is hosted at http://slapi-nis.fedorahosted.org/.
This project is hosted at https://pagure.io/slapi-nis/.
AC_INIT(slapi-nis,0.56.1)
AC_INIT(slapi-nis,0.56.2)
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE(foreign)
LT_INIT([disable-static])
......@@ -361,8 +361,13 @@ if test "x$use_nsswitch" != xno ; then
SSS_NSS_IDMAP_LIBS=
fi
fi
AC_SUBST(SSS_NSS_IDMAP_CFLAGS)
AC_SUBST(SSS_NSS_IDMAP_LIBS)
AC_CHECK_LIB(sss_nss_idmap,sss_nss_getpwnam_timeout)
if test "x$ac_cv_lib_sss_nss_idmap_sss_nss_getpwnam_timeout" = xyes ; then
AC_DEFINE(USE_SSS_NSS_TIMEOUT,1,[Use extended NSS API provided by SSSD])
fi
if test "x$use_pam" != xno ; then
AC_CHECK_HEADERS(security/pam_appl.h)
......@@ -384,6 +389,7 @@ if test "x$use_nsswitch" != xno ; then
fi
AC_DEFINE(USE_NSSWITCH,1,[Use nsswitch API to lookup users and groups not found in the LDAP tree])
fi
AM_CONDITIONAL([USE_SSS_NSS_TIMEOUT], [test "x$ac_cv_lib_sss_nss_idmap_sss_nss_getpwnam_timeout" = xyes])
use_idviews=true
AC_ARG_WITH(idviews,
......
......@@ -10,7 +10,7 @@
%endif
Name: slapi-nis
Version: 0.56.1
Version: 0.56.2
Release: 1%{?dist}
Summary: NIS Server and Schema Compatibility plugins for Directory Server
Group: System Environment/Daemons
......@@ -19,10 +19,10 @@ URL: http://slapi-nis.fedorahosted.org/
Source0: https://fedorahosted.org/releases/s/l/slapi-nis/slapi-nis-%{version}.tar.gz
#Source1: https://fedorahosted.org/releases/s/l/slapi-nis/slapi-nis-%{version}.tar.gz.sig
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: 389-ds-base-devel > 1.3.5.6, %{ldap_impl}-devel
BuildRequires: 389-ds-base-devel >= 1.3.5.6, %{ldap_impl}-devel
BuildRequires: nspr-devel, nss-devel, /usr/bin/rpcgen
%if 0%{?fedora} > 18 || 0%{?rhel} > 6
BuildRequires: libsss_nss_idmap-devel
BuildRequires: libsss_nss_idmap-devel > 1.16.0-5
%define sss_nss_opts --with-sss-nss-idmap --with-idviews
%else
%define sss_nss_opts %{nil}
......@@ -39,6 +39,7 @@ BuildRequires: libtirpc-devel
%if 0%{?rhel} > 0 && 0%{?rhel} < 7
ExclusiveArch: x86_64 %{ix86}
%endif
Requires: 389-ds-base >= 1.3.5.6
%description
This package provides two plugins for Red Hat and 389 Directory Server.
......@@ -85,22 +86,41 @@ rm -rf $RPM_BUILD_ROOT
%{_sbindir}/nisserver-plugin-defs
%changelog
* Sun Aug 07 2016 Alexander Bokovoy <abokovoy@redhat.com> - 0.56.1-1
* Fri Jan 19 2018 Alexander Bokovoy <abokovoy@redhat.com> - 0.56.2-1
- New upstream release
- Use extended SSSD API to signal that an entry should not be cached anymore
- Add support for timeout-based NSS queries with libsss_nss_idmap
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.56.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
* Mon Aug 08 2016 Alexander Bokovoy <abokovoy@redhat.com> - 0.56.1-1
- Support querying external users by UPN alias
- Don't clobber target of the pblock for ID views
* Mon Jun 20 2016 Alexander Bokovoy <abokovoy@redhat.com> - 0.56.0-2
- Updated upstream tarball
* Mon Jun 20 2016 Alexander Bokovoy <abokovoy@redhat.com> - 0.56-1
- Add priming thread to populate the map cache without blocking the DS
- Add support for changing passwords for users from a primary tree
- requires DS 1.3.5.6 or later
* Mon May 30 2016 Alexander Bokovoy <abokovoy@redhat.com> - 0.55-3
- Add support to properly shutdown priming cache from RHEL 7.2.4
* Fri Feb 05 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.55-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
* Tue Jan 26 2016 Alexander Bokovoy <abokovoy@redhat.com> - 0.55-1
- Support external members of IPA groups in schema compat
- Support bind over ID overrides when uid is not overridden
- Populate schema compat trees in parallel to LDAP server startup
* Fri Jun 19 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.54.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
* Thu Mar 26 2015 Alexander Bokovoy <abokovoy@redhat.com> - 0.54.2-1
- CVE-2015-0283 slapi-nis: infinite loop in getgrnam_r() and getgrgid_r()
- CVE-2015-0283 slapi-nis: infinite loop in getgrnam_r() and getgrgid_r() (#1206049)
- Make sure nss_sss.so.2 module is used directly
- Allow building slapi-nis with ID views against 389-ds-base from RHEL7.0/CentOS7.0 releases
......@@ -113,6 +133,12 @@ rm -rf $RPM_BUILD_ROOT
- Allow searching SSSD-provided users as memberUid case-insensitevly
Fixes bug #1130131
* Mon Aug 18 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.53-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
* Sun Jun 08 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.53-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
* Tue Apr 22 2014 Nalin Dahyabhai <nalin@redhat.com> - 0.53-1
- correct the default NIS map settings for hosts.byname and hosts.byaddr,
from report by Rik Megens
......
......@@ -68,8 +68,17 @@ schemacompat_plugin_la_LIBADD = $(LDAP_LIBS) $(RUNTIME_LIBS) $(LIBPTHREAD) $(CON
if USE_NSSWITCH
schemacompat_plugin_la_CFLAGS += $(SSS_NSS_IDMAP_CFLAGS)
schemacompat_plugin_la_SOURCES += back-sch-nss.c
schemacompat_plugin_la_SOURCES += back-sch-nss.c back-sch-nss.h
schemacompat_plugin_la_LIBADD += $(SSS_NSS_IDMAP_LIBS)
# We have two backends for nss operations:
# (1) directly loading nss_sss.so.2
# (2) using timeout-enabled API from libsss_nss_idmap
# We prefer (2) if available
if USE_SSS_NSS_TIMEOUT
schemacompat_plugin_la_SOURCES += back-sch-sss_idmap.c
else
schemacompat_plugin_la_SOURCES += back-sch-nss_sss.c
endif
endif
if USE_PAM
......
......@@ -1014,6 +1014,34 @@ backend_check_empty(struct plugin_state *state,
}
}
bool_t
backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e)
{
return FALSE;
}
bool_t
backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e_pre,
Slapi_Entry *e_post)
{
return FALSE;
}
bool_t
backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e)
{
return FALSE;
}
/* Scan for the list of configured domains and maps. */
void
backend_startup(Slapi_PBlock *pb, struct plugin_state *state)
......
......@@ -121,7 +121,7 @@ idview_process_overrides(struct backend_search_cbdata *cbdata,
"createtimestamp", "modifytimestamp", "parentid",
"entryusn", "entryid", "entrydn", "ipaoriginaluid",
"ipaanchoruuid", "nsuniqueid", "ipasshpubkey", NULL };
char *new_dn = NULL, *new_key = NULL, *sep = NULL, *new_val = NULL;
char *new_dn = NULL, *sep = NULL, *new_val = NULL;
char *override_type = NULL;
Slapi_Entry *override_entry = NULL;
Slapi_Attr *anchor = NULL, *id_attr = NULL;
......
......@@ -28,7 +28,6 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <dlfcn.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
......@@ -52,12 +51,12 @@
#include "map.h"
#include "back-sch.h"
#include "format.h"
#include "back-sch-nss.h"
static int
bvstrprefix(const struct berval *bval, const char *s)
{
size_t len;
int c;
len = strlen(s);
if (len < bval->bv_len) {
......@@ -186,47 +185,6 @@ backend_search_filter_has_cn_uid(Slapi_Filter *filter, void *arg)
return SLAPI_FILTER_SCAN_CONTINUE;
}
static char *
backend_build_dn(const char *attribute, const char *value,
const char *container_sdn)
{
Slapi_RDN *rdn;
Slapi_DN *sdn;
char *val, *dn = NULL;
const char *ndn, *hexchars = "0123456789ABCDEF";
int i;
val = malloc(strlen(value) * 3 + 1);
if (val == NULL) {
return NULL;
}
rdn = slapi_rdn_new();
if (rdn == NULL) {
free(val);
return NULL;
}
for (i = 0; value[i] != '\0'; i++) {
val[i * 3] = '\\';
val[i * 3 + 1] = hexchars[(value[i] & 0xf0) >> 4];
val[i * 3 + 2] = hexchars[value[i] & 0xf];
}
val[i * 3] = '\0';
if (slapi_rdn_add(rdn, attribute, val) == 1) {
sdn = slapi_sdn_new_dn_byval(container_sdn);
if (sdn != NULL) {
sdn = slapi_sdn_add_rdn(sdn, rdn);
ndn = slapi_sdn_get_ndn(sdn);
if (ndn != NULL) {
dn = slapi_ch_strdup(ndn);
}
slapi_sdn_free(&sdn);
}
}
free(val);
slapi_rdn_free(&rdn);
return dn;
}
static Slapi_Entry *
backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
char *container_sdn,
......@@ -257,7 +215,7 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
return NULL;
}
dn = backend_build_dn("uid", name, container_sdn);
dn = format_build_dn("uid", name, container_sdn);
if (dn == NULL) {
slapi_log_error(SLAPI_LOG_FATAL,
cbdata->state->plugin_desc->spd_id,
......@@ -335,143 +293,6 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
return entry;
}
/* Possible results of lookup using a nss_* function.
* Note: don't include nss.h as its path gets overriden by NSS library */
enum nss_status
{
NSS_STATUS_TRYAGAIN = -2,
NSS_STATUS_UNAVAIL,
NSS_STATUS_NOTFOUND,
NSS_STATUS_SUCCESS,
NSS_STATUS_RETURN
};
struct nss_ops_ctx {
void *dl_handle;
enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*setpwent)(void);
enum nss_status (*getpwent_r)(struct passwd *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*endpwent)(void);
enum nss_status (*getgrnam_r)(const char *name, struct group *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*setgrent)(void);
enum nss_status (*getgrent_r)(struct group *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*endgrent)(void);
enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
long int *start, long int *size,
gid_t **groups, long int limit,
int *errnop);
};
void backend_nss_init_context(struct nss_ops_ctx **nss_context)
{
struct nss_ops_ctx *ctx = NULL;
if (nss_context == NULL) {
return;
}
ctx = calloc(1, sizeof(struct nss_ops_ctx));
*nss_context = ctx;
if (ctx == NULL) {
return;
}
ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW);
if (ctx->dl_handle == NULL) {
goto fail;
}
ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r");
if (ctx->getpwnam_r == NULL) {
goto fail;
}
ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r");
if (ctx->getpwuid_r == NULL) {
goto fail;
}
ctx->setpwent = dlsym(ctx->dl_handle, "_nss_sss_setpwent");
if (ctx->setpwent == NULL) {
goto fail;
}
ctx->getpwent_r = dlsym(ctx->dl_handle, "_nss_sss_getpwent_r");
if (ctx->getpwent_r == NULL) {
goto fail;
}
ctx->endpwent = dlsym(ctx->dl_handle, "_nss_sss_endpwent");
if (ctx->endpwent == NULL) {
goto fail;
}
ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r");
if (ctx->getgrnam_r == NULL) {
goto fail;
}
ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r");
if (ctx->getgrgid_r == NULL) {
goto fail;
}
ctx->setgrent = dlsym(ctx->dl_handle, "_nss_sss_setgrent");
if (ctx->setgrent == NULL) {
goto fail;
}
ctx->getgrent_r = dlsym(ctx->dl_handle, "_nss_sss_getgrent_r");
if (ctx->getgrent_r == NULL) {
goto fail;
}
ctx->endgrent = dlsym(ctx->dl_handle, "_nss_sss_endgrent");
if (ctx->endgrent == NULL) {
goto fail;
}
ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn");
if (ctx->initgroups_dyn == NULL) {
goto fail;
}
return;
fail:
backend_nss_free_context(nss_context);
return;
}
void
backend_nss_free_context(struct nss_ops_ctx **nss_context)
{
if (nss_context == NULL) {
return;
}
if ((*nss_context)->dl_handle != NULL) {
dlclose((*nss_context)->dl_handle);
}
free((*nss_context));
*nss_context = NULL;
}
static Slapi_Entry **
backend_retrieve_user_entry_from_nsswitch(char *user_name, bool_t is_uid,
......@@ -497,13 +318,13 @@ repeat:
}
if (is_uid) {
rc = ctx->getpwuid_r((uid_t) atoll(user_name), &pwd,
rc = backend_nss_getpwuid(ctx, (uid_t) atoll(user_name), &pwd,
cbdata->nsswitch_buffer,
cbdata->nsswitch_buffer_len, &lerrno);
cbdata->nsswitch_buffer_len, &result, &lerrno);
} else {
rc = ctx->getpwnam_r(user_name, &pwd,
rc = backend_nss_getpwnam(ctx, user_name, &pwd,
cbdata->nsswitch_buffer,
cbdata->nsswitch_buffer_len, &lerrno);
cbdata->nsswitch_buffer_len, &result, &lerrno);
}
if ((rc != NSS_STATUS_SUCCESS)) {
......@@ -556,7 +377,7 @@ backend_make_group_entry_from_nsswitch_group(struct group *grp,
return NULL;
}
dn = backend_build_dn("cn", grp->gr_name, container_sdn);
dn = format_build_dn("cn", grp->gr_name, container_sdn);
if (dn == NULL) {
slapi_log_error(SLAPI_LOG_FATAL,
cbdata->state->plugin_desc->spd_id,
......@@ -632,13 +453,13 @@ repeat:
}
if (is_gid) {
rc = ctx->getgrgid_r((gid_t) atoll(group_name), &grp,
rc = backend_nss_getgrgid(ctx, (gid_t) atoll(group_name), &grp,
cbdata->nsswitch_buffer,
cbdata->nsswitch_buffer_len, &lerrno);
cbdata->nsswitch_buffer_len, &result, &lerrno);
} else {
rc = ctx->getgrnam_r(group_name, &grp,
rc = backend_nss_getgrnam(ctx, group_name, &grp,
cbdata->nsswitch_buffer,
cbdata->nsswitch_buffer_len, &lerrno);
cbdata->nsswitch_buffer_len, &result, &lerrno);
}
if ((rc != NSS_STATUS_SUCCESS)) {
if (lerrno == ERANGE) {
......@@ -692,9 +513,9 @@ repeat:
return NULL;
}
rc = ctx->getgrgid_r(gid, &grp,
rc = backend_nss_getgrgid(ctx, gid, &grp,
cbdata->nsswitch_buffer,
cbdata->nsswitch_buffer_len, &lerrno);
cbdata->nsswitch_buffer_len, &result, &lerrno);
if ((rc != NSS_STATUS_SUCCESS)) {
if (lerrno == ERANGE) {
......@@ -730,8 +551,7 @@ backend_retrieve_group_list_from_nsswitch(char *user_name, char *container_sdn,
int i, idx;
struct nss_ops_ctx *ctx = NULL;
int lerrno = 0;
long int ngroups = 0;
long int start = 0;
int ngroups = 0;
enum nss_status rc;
ctx = cbdata->state->nss_context;
......@@ -743,9 +563,9 @@ repeat:
return NULL;
}
rc = ctx->getpwnam_r(user_name, &pwd,
rc = backend_nss_getpwnam(ctx, user_name, &pwd,
cbdata->nsswitch_buffer,
cbdata->nsswitch_buffer_len, &lerrno);
cbdata->nsswitch_buffer_len, &pwd_result, &lerrno);
if ((rc != NSS_STATUS_SUCCESS)) {
if (lerrno == ERANGE) {
......@@ -764,19 +584,15 @@ repeat:
}
ngroups = 32;
start = 0;
grouplist = malloc(sizeof(gid_t) * ngroups);
if (grouplist == NULL) {
return NULL;
}
grouplist[0] = pwd.pw_gid;
start++;
do {
rc = ctx->initgroups_dyn(user_name, pwd.pw_gid,
&start, &ngroups, &grouplist,
-1, &lerrno);
rc = backend_nss_getgrouplist(ctx, user_name, pwd.pw_gid,
grouplist, &ngroups,
&lerrno);
if ((rc != NSS_STATUS_SUCCESS)) {
tmp_list = realloc(grouplist, ngroups * sizeof(gid_t));
if (tmp_list == NULL) {
......@@ -856,7 +672,7 @@ void
backend_search_nsswitch(struct backend_set_data *set_data,
struct backend_search_cbdata *cbdata)
{
int result, rc;
int result;
struct backend_search_filter_config config =
{FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL, NULL, NULL};
struct backend_staged_search *staged = NULL;
......
/*
* Copyright 2017 Red Hat, Inc.
*
* 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; version 2 of the License.
*
* 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, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
*/
#ifndef back_sch_nss_h
#define back_sch_nss_h
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
/* Possible results of lookup using a nss_* function.
* Note: don't include nss.h as its path gets overriden by NSS library */
enum nss_status
{
NSS_STATUS_TRYAGAIN = -2,
NSS_STATUS_UNAVAIL,
NSS_STATUS_NOTFOUND,
NSS_STATUS_SUCCESS,
NSS_STATUS_RETURN
};
struct nss_ops_ctx;
enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context,
const char *name, struct passwd *pwd,
char *buffer, size_t buflen,
struct passwd **result,
int *lerrno);
enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context,
uid_t uid, struct passwd *pwd,
char *buffer, size_t buflen,
struct passwd **result,
int *lerrno);
enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context,
const char *name, struct group *grp,
char *buffer, size_t buflen,
struct group **result,
int *lerrno);
enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context,
gid_t gid, struct group *grp,
char *buffer, size_t buflen,
struct group **result,
int *lerrno);
enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context,
const char *name, gid_t group,
gid_t *groups, int *ngroups,
int *lerrno);
#endif /* back_sch_nss_h */
/*
* Copyright 2013-2017 Red Hat, Inc.
*
* 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; version 2 of the License.
*
* 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, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <dlfcn.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <sys/param.h>
#include "back-sch-nss.h"
struct nss_ops_ctx {
void *dl_handle;
long int initgroups_start;
enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*getgrnam_r)(const char *name, struct group *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
char *buffer, size_t buflen, int *errnop);
enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
long int *start, long int *size,
gid_t **groups, long int limit,
int *errnop);
};
void backend_nss_free_context(struct nss_ops_ctx **nss_context)
{
if ((nss_context == NULL) || (*nss_context == NULL)) {
return;
}
if ((*nss_context)->dl_handle != NULL) {
dlclose((*nss_context)->dl_handle);
}
free((*nss_context));
*nss_context = NULL;
}
int backend_nss_init_context(struct nss_ops_ctx **nss_context)
{
struct nss_ops_ctx *ctx = NULL;
if (nss_context == NULL) {
return EINVAL;
}
ctx = calloc(1, sizeof(struct nss_ops_ctx));
if (ctx == NULL) {
return ENOMEM;
}
*nss_context = ctx;
ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW);
if (ctx->dl_handle == NULL) {
goto fail;
}
ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r");
if (ctx->getpwnam_r == NULL) {
goto fail;
}
ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r");
if (ctx->getpwuid_r == NULL) {
goto fail;
}
ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r");
if (ctx->getgrnam_r == NULL) {
goto fail;
}
ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r");
if (ctx->getgrgid_r == NULL) {
goto fail;
}
ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn");
if (ctx->initgroups_dyn == NULL) {
goto fail;
}
return 0;
fail:
backend_nss_free_context(nss_context);
return EINVAL;
}
/* Following three functions cannot be implemented with nss_sss.so.2
* As result, we simply do nothing here */
void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
unsigned int timeout) {
/* no operation */
}
void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
const char *name) {
/* no operation */
}
void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
const char *name) {
/* no operation */
}
enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context,
const char *name, struct passwd *pwd,
char *buffer, size_t buflen,
struct passwd **result,
int *lerrno) {
enum nss_status ret;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = nss_context->getpwnam_r(name, pwd,
buffer, buflen,
lerrno);
if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
*result = pwd;
*lerrno = 0;
}
return ret;
}
enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context,
uid_t uid, struct passwd *pwd,
char *buffer, size_t buflen,
struct passwd **result,
int *lerrno) {
enum nss_status ret;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = nss_context->getpwuid_r(uid, pwd,
buffer, buflen,
lerrno);
if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
*result = pwd;
*lerrno = 0;
}
return ret;
}
enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context,
const char *name, struct group *grp,
char *buffer, size_t buflen,
struct group **result,
int *lerrno) {
enum nss_status ret;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = nss_context->getgrnam_r(name, grp,
buffer, buflen,
lerrno);
if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
*result = grp;
*lerrno = 0;
}
return ret;
}
enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context,
gid_t gid, struct group *grp,
char *buffer, size_t buflen,
struct group **result,
int *lerrno) {
enum nss_status ret;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = nss_context->getgrgid_r(gid, grp,
buffer, buflen,
lerrno);
if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
*result = grp;
*lerrno = 0;
}
return ret;
}
enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context,
const char *name, gid_t group,
gid_t *groups, int *ngroups,
int *lerrno) {
enum nss_status ret = NSS_STATUS_UNAVAIL;
long int tsize = MAX (1, *ngroups);
gid_t *newgroups = NULL;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
newgroups = (gid_t *) calloc (tsize, sizeof (gid_t));
if (newgroups == NULL) {
*lerrno = ENOMEM;
return NSS_STATUS_TRYAGAIN;
}
newgroups[0] = group;
nss_context->initgroups_start = 1;
ret = nss_context->initgroups_dyn(name, group,
&nss_context->initgroups_start,
&tsize, &newgroups,
-1, lerrno);
(void) memcpy(groups, newgroups,
MIN(*ngroups, nss_context->initgroups_start) * sizeof(gid_t));
free(newgroups);
if (*ngroups < nss_context->initgroups_start) {
ret = NSS_STATUS_TRYAGAIN;
*lerrno = ERANGE;
}
*ngroups = (int) nss_context->initgroups_start;
nss_context->initgroups_start = 0;
return ret;
}
/*
* Copyright 2013-2017 Red Hat, Inc.
*
* 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; version 2 of the License.
*
* 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, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include "back-sch-nss.h"
/* SSSD only exposes *_timeout() variants if the following symbol is defined */
#define IPA_389DS_PLUGIN_HELPER_CALLS
#include <sss_nss_idmap.h>
struct nss_ops_ctx {
unsigned int timeout;
};
static enum nss_status __convert_sss_nss2nss_status(int errcode) {
switch(errcode) {
case 0:
return NSS_STATUS_SUCCESS;
case ENOENT:
return NSS_STATUS_NOTFOUND;
case ETIME:
/* fall-through */
case ERANGE:
return NSS_STATUS_TRYAGAIN;
case ETIMEDOUT:
/* fall-through */
default:
return NSS_STATUS_UNAVAIL;
}
return NSS_STATUS_UNAVAIL;
}
int backend_nss_init_context(struct nss_ops_ctx **nss_context)
{
struct nss_ops_ctx *ctx = NULL;
if (nss_context == NULL) {
return EINVAL;
}
ctx = calloc(1, sizeof(struct nss_ops_ctx));
if (ctx == NULL) {
return ENOMEM;
}
*nss_context = ctx;
return 0;
}
void backend_nss_free_context(struct nss_ops_ctx **nss_context)
{
if ((nss_context == NULL) || (*nss_context == NULL)) {
return;
}
free((*nss_context));
*nss_context = NULL;
}
void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
unsigned int timeout) {
if (nss_context == NULL) {
return;
}
nss_context->timeout = timeout;
}
void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
const char *name) {
if (nss_context == NULL) {
return;
}
(void) sss_nss_getpwnam_timeout(name, NULL,
NULL, 0,
NULL,
SSS_NSS_EX_FLAG_INVALIDATE_CACHE,
nss_context->timeout);
}
void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
const char *name) {
if (nss_context == NULL) {
return;
}
(void) sss_nss_getgrnam_timeout(name, NULL,
NULL, 0,
NULL,
SSS_NSS_EX_FLAG_INVALIDATE_CACHE,
nss_context->timeout);
}
enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context,
const char *name, struct passwd *pwd,
char *buffer, size_t buflen,
struct passwd **result,
int *lerrno) {
int ret = 0;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = sss_nss_getpwnam_timeout(name, pwd,
buffer, buflen,
result,
SSS_NSS_EX_FLAG_NO_FLAGS,
nss_context->timeout);
/* SSSD uses the same infrastructure to handle sss_nss_get* calls
* as nss_sss.so.2 module where 'int *errno' is passed to the helper
* but writes down errno into return code so we propagate it in case
* of error and translate the return code */
if (lerrno != NULL) {
*lerrno = ret;
}
return __convert_sss_nss2nss_status(ret);
}
enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context,
uid_t uid, struct passwd *pwd,
char *buffer, size_t buflen,
struct passwd **result,
int *lerrno) {
int ret = 0;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = sss_nss_getpwuid_timeout(uid, pwd,
buffer, buflen,
result,
SSS_NSS_EX_FLAG_NO_FLAGS,
nss_context->timeout);
/* SSSD uses the same infrastructure to handle sss_nss_get* calls
* as nss_sss.so.2 module where 'int *errno' is passed to the helper
* but writes down errno into return code so we propagate it in case
* of error and translate the return code */
if (lerrno != NULL) {
*lerrno = ret;
}
return __convert_sss_nss2nss_status(ret);
}
enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context,
const char *name, struct group *grp,
char *buffer, size_t buflen,
struct group **result,
int *lerrno) {
int ret = 0;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = sss_nss_getgrnam_timeout(name, grp,
buffer, buflen,
result,
SSS_NSS_EX_FLAG_NO_FLAGS,
nss_context->timeout);
/* SSSD uses the same infrastructure to handle sss_nss_get* calls
* as nss_sss.so.2 module where 'int *errno' is passed to the helper
* but writes down errno into return code so we propagate it in case
* of error and translate the return code */
if (lerrno != NULL) {
*lerrno = ret;
}
return __convert_sss_nss2nss_status(ret);
}
enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context,
gid_t gid, struct group *grp,
char *buffer, size_t buflen,
struct group **result,
int *lerrno) {
int ret = 0;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = sss_nss_getgrgid_timeout(gid, grp,
buffer, buflen,
result,
SSS_NSS_EX_FLAG_NO_FLAGS,
nss_context->timeout);
/* SSSD uses the same infrastructure to handle sss_nss_get* calls
* as nss_sss.so.2 module where 'int *errno' is passed to the helper
* but writes down errno into return code so we propagate it in case
* of error and translate the return code */
if (lerrno != NULL) {
*lerrno = ret;
}
return __convert_sss_nss2nss_status(ret);
}
enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context,
const char *name, gid_t group,
gid_t *groups, int *ngroups,
int *lerrno) {
int ret = 0;
if (nss_context == NULL) {
return NSS_STATUS_UNAVAIL;
}
ret = sss_nss_getgrouplist_timeout(name, group,
groups, ngroups,
SSS_NSS_EX_FLAG_NO_FLAGS,
nss_context->timeout);
/* SSSD uses the same infrastructure to handle sss_nss_get* calls
* as nss_sss.so.2 module where 'int *errno' is passed to the helper
* but writes down errno into return code so we propagate it in case
* of error and translate the return code */
if (lerrno != NULL) {
*lerrno = ret;
}
return __convert_sss_nss2nss_status(ret);
}
......@@ -33,6 +33,7 @@
#ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H
#include <nspr.h>
#include <plhash.h>
#include <plstr.h>
#include <nss.h>
#include <dirsrv/slapi-plugin.h>
#else
......@@ -506,7 +507,7 @@ backend_set_process_external_members(Slapi_PBlock *pb,
/* This group must exist because it exists in the original tree
* but as dirsrv was restarted, SSSD might still consider its domain offline. */
is_group_exists = backend_retrieve_from_nsswitch(&staged, &cbdata);
if (!is_group_exists) {
if (!is_group_exists && !slapi_is_shutting_down()) {
slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
"group \"%s\" does not exist because SSSD is offline.\n",
staged.name);
......@@ -2099,6 +2100,193 @@ backend_write_cb(Slapi_PBlock *pb, struct plugin_state *state)
return ret;
}
#ifdef USE_IPA_IDVIEWS
/* Check if ID override applies to an entry in our map cache
* and remove the entry in case it does. */
static bool_t
backend__get_original_uid_and_ndn(Slapi_Entry *e,
char **original_uid,
const char **original_anchor)
{
char **elem = NULL;
char *v = NULL;
char *ndn = NULL;
char *view = NULL;
int n_elem = 0;
int i = 0;
if (e == NULL) {
return FALSE;
}
elem = slapi_entry_attr_get_charray_ext(e, "objectClass", &n_elem);
if (elem == NULL) {
/* weird, objectClass should be existing */
return FALSE;
}
for (i=0; i < n_elem; i++) {
if (strncasecmp(elem[i], "ipaOverrideAnchor", 17) == 0) {
break;
}
}
slapi_ch_array_free(elem);
if (i == n_elem) {
/* This is not an override, bail out */
return FALSE;
}
ndn = slapi_entry_get_ndn(e);
if (ndn == NULL) {
return FALSE;
}
view = PL_strcasestr(ndn, "cn=Default Trust View,");
if (view == NULL || view == ndn) {
return FALSE;
}
/* This is an ID override, we need to search for a referenced ipaOriginalUid or cn in our maps */
v = slapi_entry_attr_get_charptr(e, "ipaOriginalUid");
if (v == NULL) {
v = slapi_entry_attr_get_charptr(e, "cn");
if (v == NULL) {
return FALSE;
}
}
*original_uid = v;
*original_anchor = ndn;
return TRUE;
}
bool_t
backend_entry_evict_if_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e)
{
struct backend_set_data *set_data;
struct plugin_state *state = NULL;
char *id = NULL;
char *original_uid = NULL;
const char *original_anchor = NULL;
const char *rdn_attribute[] = {NULL, "uid=%s,%s,%s", "cn=%s,%s,%s"};
bool_t result = FALSE;
set_data = shared_set_data;
/* We only interested in NSSWITCH-capable maps */
if (set_data->check_nsswitch == SCH_NSSWITCH_NONE) {
return FALSE;
}
/* See if the entry pre modification had original UID */
if (!backend__get_original_uid_and_ndn(e,
&original_uid,
&original_anchor)) {
return FALSE;
}
id = slapi_ch_smprintf(rdn_attribute[set_data->check_nsswitch],
original_uid, set, group);
if (id == NULL) {
slapi_ch_free_string(&original_uid);
return FALSE;
}
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
result = map_data_check_entry(state, group, set, id);
if (result) {
slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
"evicted entry %s due to changed content of ID override %s\n",
id, original_anchor);
/* An entry corresponding to our target is found, evict it */
map_data_unset_entry(state, group, set, id);
/* Signal to SSSD that this entry is not cached anymore */
switch(set_data->check_nsswitch) {
case SCH_NSSWITCH_USER:
backend_nss_evict_user(state->nss_context, original_uid);
break;
case SCH_NSSWITCH_GROUP:
backend_nss_evict_group(state->nss_context, original_uid);
break;
default:
break;
}
}
slapi_ch_free_string(&id);
slapi_ch_free_string(&original_uid);
return result;
}
bool_t
backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e)
{
return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e);
}
bool_t
backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e_pre,
Slapi_Entry *e_post)
{
return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e_pre);
}
bool_t
backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e)
{
return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e);
}
#else
bool_t
backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e)
{
return FALSE;
}
bool_t
backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e_pre,
Slapi_Entry *e_post)
{
return FALSE;
}
bool_t
backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e)
{
return FALSE;
}
#endif
static int
backend_pre_write_cb(Slapi_PBlock *pb)
{
......
......@@ -137,7 +137,6 @@ struct backend_search_filter_config {
#define LDAP_EXTOP_PASSMOD_TAG_NEWPWD 0x82U
typedef int (*IFP)();
static int backend_passwdmod_extop(Slapi_PBlock *pb);
typedef struct backend_extop_handlers {
char *oid;
IFP extop_fct;
......@@ -152,10 +151,17 @@ typedef struct backend_extop_handlers {
int backend_analyze_search_filter(Slapi_Filter *filter, struct backend_search_filter_config *config);
/* Operations against nsswitch API */
/* NSS backend operations implemented using either nss_sss.so.2 or libsss_nss_idmap API */
struct nss_ops_ctx;
void backend_nss_init_context(struct nss_ops_ctx **nss_context);
int backend_nss_init_context(struct nss_ops_ctx **nss_context);
void backend_nss_free_context(struct nss_ops_ctx **nss_context);
void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
unsigned int timeout);
void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
const char *name);
void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
const char *name);
void backend_search_nsswitch(struct backend_set_data *set_data,
struct backend_search_cbdata *cbdata);
......
......@@ -1856,11 +1856,21 @@ backend_shr_add_entry_cb(const char *group, const char *set, bool_t secure,
/* If the entry doesn't match the set, skip it. */
if (!backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e)) {
/* Give backend a chance to perform other operations on the add op.
* For example, ID override addition in FreeIPA need to be noted to
* evict AD user/group entries from a map cache while ID overrides
* themselves aren't present in any map.
* Note that we could do this as a part of backend_shr_entry_matches_set()
* but it is better to isolate this operation in a separate call. */
if (!backend_entry_is_add_related(group, set, secure,
set_data, cbdata->pb,
cbdata->e)) {
slapi_log_error(SLAPI_LOG_PLUGIN,
cbdata->state->plugin_desc->spd_id,
"entry \"%s\" does not belong in "
"\"%s\"/\"%s\"\n",
cbdata->ndn, group, set);
}
return TRUE;
}
......@@ -2010,6 +2020,16 @@ backend_shr_modify_entry_cb(const char *group, const char *set, bool_t flag,
cbdata->e_post) &&
!backend_shr_entry_matches_set(set_data, cbdata->pb,
cbdata->e_pre)) {
/* Give backend a chance to perform other operations on the modify op.
* For example, ID override updates in FreeIPA need to be noted to
* evict AD user/group entries from a map cache while ID overrides
* themselves aren't present in any map.
* Note that we could do this as a part of backend_shr_entry_matches_set()
* but it is better to isolate this operation in a separate call. */
if (!backend_entry_is_modify_related(group, set, flag,
set_data, cbdata->pb,
cbdata->e_pre,
cbdata->e_post)) {
slapi_log_error(SLAPI_LOG_PLUGIN,
cbdata->state->plugin_desc->spd_id,
"\"%s\" not in \"%s\"/\"%s\", "
......@@ -2017,6 +2037,7 @@ backend_shr_modify_entry_cb(const char *group, const char *set, bool_t flag,
cbdata->ndn,
set_data->group,
set_data->set);
}
return TRUE;
}
if (set_data->skip_uninteresting_updates &&
......@@ -2631,6 +2652,16 @@ backend_shr_delete_entry_cb(const char *group, const char *set, bool_t flag,
group, set, set_data->group, set_data->set,
cbdata->ndn);
map_data_unset_entry(cbdata->state, group, set, cbdata->ndn);
} else {
/* Give backend a chance to perform other operations on the delete op.
* For example, ID override removal in FreeIPA need to be noted to
* evict AD user/group entries from a map cache while ID overrides
* themselves aren't present in any map.
* Note that we could do this as a part of backend_shr_entry_matches_set()
* but it is better to isolate this operation in a separate call. */
(void) backend_entry_is_delete_related(group, set, flag,
set_data, cbdata->pb,
cbdata->e);
}
return TRUE;
}
......
......@@ -115,4 +115,24 @@ void backend_update_params(Slapi_PBlock *pb, struct plugin_state *state);
bool_t backend_shr_is_caller(struct plugin_state *state,
struct slapi_pblock *pb);
/* Check if an operation is performed on an entry that is related to
* any entry in the set. This allows to catch changes of the entries that
* aren't directly included in the map set but should affect the set. */
bool_t
backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e_pre,
Slapi_Entry *e_post);
bool_t
backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e);
bool_t
backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
void *shared_set_data,
Slapi_PBlock *pb,
Slapi_Entry *e);
#endif
......@@ -4825,3 +4825,44 @@ format_escape_for_filter(const char *unescaped)
}
return ret;
}
char *
format_build_dn(const char *attribute, const char *value,
const char *container_sdn)
{
Slapi_RDN *rdn;
Slapi_DN *sdn;
char *val, *dn = NULL;
const char *ndn, *hexchars = "0123456789ABCDEF";
int i;
val = malloc(strlen(value) * 3 + 1);
if (val == NULL) {
return NULL;
}
rdn = slapi_rdn_new();
if (rdn == NULL) {
free(val);
return NULL;
}
for (i = 0; value[i] != '\0'; i++) {
val[i * 3] = '\\';
val[i * 3 + 1] = hexchars[(value[i] & 0xf0) >> 4];
val[i * 3 + 2] = hexchars[value[i] & 0xf];
}
val[i * 3] = '\0';
if (slapi_rdn_add(rdn, attribute, val) == 1) {
sdn = slapi_sdn_new_dn_byval(container_sdn);
if (sdn != NULL) {
sdn = slapi_sdn_add_rdn(sdn, rdn);
ndn = slapi_sdn_get_ndn(sdn);
if (ndn != NULL) {
dn = slapi_ch_strdup(ndn);
}
slapi_sdn_free(&sdn);
}
}
free(val);
slapi_rdn_free(&rdn);
return dn;
}
......@@ -83,4 +83,6 @@ char **format_get_data_set(struct plugin_state *state,
unsigned int **data_lengths);
char *format_escape_for_filter(const char *unescaped);
char *format_build_dn(const char *attribute, const char *value,
const char *container_sdn);
#endif
......@@ -104,6 +104,8 @@ plugin_startup(Slapi_PBlock *pb)
struct plugin_state *state;
Slapi_Entry *plugin_entry = NULL;
Slapi_DN *pluginsdn = NULL;
unsigned int nss_timeout = 10000;
int ret = 0;
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
slapi_pblock_get(pb, SLAPI_TARGET_SDN, &pluginsdn);
......@@ -113,7 +115,6 @@ plugin_startup(Slapi_PBlock *pb)
slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id,
"scheman compat plugin_startup: unable to retrieve plugin DN\n");
return -1;
} else {
state->plugin_base = slapi_ch_strdup(slapi_sdn_get_dn(pluginsdn));
slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
......@@ -124,13 +125,25 @@ plugin_startup(Slapi_PBlock *pb)
}
state->pam_lock = wrap_new_rwlock();
backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
ret = backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
if (ret != 0) {
slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
"failed to intiialize nsswitch backend: [%d]!\n",
ret);
return -1;
}
if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
(plugin_entry != NULL)) {
state->use_entry_cache = backend_shr_get_vattr_boolean(state, plugin_entry,
"slapi-entry-cache",
1);
nss_timeout = backend_shr_get_vattr_uint(state, plugin_entry,
"slapi-nss-timeout",
10000);
}
backend_nss_set_timeout(state->nss_context, nss_timeout);
state->cached_entries_lock = wrap_new_rwlock();
wrap_rwlock_wrlock(state->cached_entries_lock);
state->cached_entries = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareValues, 0, 0);
......