Imported Upstream version 4.6.2
This commit is contained in:
84
daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am
Normal file
84
daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am
Normal file
@@ -0,0 +1,84 @@
|
||||
NULL =
|
||||
|
||||
PLUGIN_COMMON_DIR = $(srcdir)/../common
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(srcdir) \
|
||||
-I$(PLUGIN_COMMON_DIR) \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(DIRSRV_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(SSSNSSIDMAP_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_extdom_extop.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_extdom_extop_la_SOURCES = \
|
||||
ipa_extdom.h \
|
||||
ipa_extdom_extop.c \
|
||||
ipa_extdom_common.c \
|
||||
back_extdom.h \
|
||||
$(NULL)
|
||||
|
||||
libipa_extdom_extop_la_LDFLAGS = -avoid-version
|
||||
|
||||
libipa_extdom_extop_la_LIBADD = \
|
||||
$(LDAP_LIBS) \
|
||||
$(SSSNSSIDMAP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
# 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
|
||||
libipa_extdom_extop_la_SOURCES += back_extdom_sss_idmap.c
|
||||
else
|
||||
libipa_extdom_extop_la_SOURCES += back_extdom_nss_sss.c
|
||||
endif
|
||||
|
||||
|
||||
TESTS =
|
||||
check_PROGRAMS =
|
||||
|
||||
if HAVE_CMOCKA
|
||||
TESTS += extdom_cmocka_tests
|
||||
check_PROGRAMS += extdom_cmocka_tests
|
||||
endif
|
||||
|
||||
extdom_cmocka_tests_SOURCES = \
|
||||
ipa_extdom_cmocka_tests.c \
|
||||
ipa_extdom_common.c \
|
||||
back_extdom_nss_sss.c \
|
||||
$(NULL)
|
||||
extdom_cmocka_tests_CFLAGS = $(CMOCKA_CFLAGS)
|
||||
extdom_cmocka_tests_LDFLAGS = \
|
||||
-rpath $(shell pkg-config --libs-only-L dirsrv | sed -e 's/-L//') \
|
||||
$(NULL)
|
||||
extdom_cmocka_tests_LDADD = \
|
||||
$(CMOCKA_LIBS) \
|
||||
$(LDAP_LIBS) \
|
||||
$(DIRSRV_LIBS) \
|
||||
$(SSSNSSIDMAP_LIBS) \
|
||||
-ldl \
|
||||
$(NULL)
|
||||
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
ipa-extdom-extop-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
README \
|
||||
test_data \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
1281
daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.in
Normal file
1281
daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
0
daemons/ipa-slapi-plugins/ipa-extdom-extop/README
Normal file
0
daemons/ipa-slapi-plugins/ipa-extdom-extop/README
Normal file
79
daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h
Normal file
79
daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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_EXTDOM_H
|
||||
#define BACK_EXTDOM_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
|
||||
};
|
||||
|
||||
/* NSS backend operations implemented using either nss_sss.so.2 or libsss_nss_idmap API */
|
||||
struct nss_ops_ctx;
|
||||
|
||||
int back_extdom_init_context(struct nss_ops_ctx **nss_context);
|
||||
void back_extdom_free_context(struct nss_ops_ctx **nss_context);
|
||||
void back_extdom_set_timeout(struct nss_ops_ctx *nss_context,
|
||||
unsigned int timeout);
|
||||
void back_extdom_evict_user(struct nss_ops_ctx *nss_context,
|
||||
const char *name);
|
||||
void back_extdom_evict_group(struct nss_ops_ctx *nss_context,
|
||||
const char *name);
|
||||
|
||||
enum nss_status back_extdom_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 back_extdom_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 back_extdom_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 back_extdom_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 back_extdom_getgrouplist(struct nss_ops_ctx *nss_context,
|
||||
const char *name, gid_t group,
|
||||
gid_t *groups, int *ngroups,
|
||||
int *lerrno);
|
||||
|
||||
#endif /* BACK_EXTDOM_H */
|
||||
276
daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c
Normal file
276
daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* 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_extdom.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 back_extdom_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 back_extdom_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:
|
||||
back_extdom_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 back_extdom_set_timeout(struct nss_ops_ctx *nss_context,
|
||||
unsigned int timeout) {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
void back_extdom_evict_user(struct nss_ops_ctx *nss_context,
|
||||
const char *name) {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
void back_extdom_evict_group(struct nss_ops_ctx *nss_context,
|
||||
const char *name) {
|
||||
/* no operation */
|
||||
}
|
||||
|
||||
enum nss_status back_extdom_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 back_extdom_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 back_extdom_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 back_extdom_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 back_extdom_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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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_extdom.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 back_extdom_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 back_extdom_free_context(struct nss_ops_ctx **nss_context)
|
||||
{
|
||||
if ((nss_context == NULL) || (*nss_context == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
free((*nss_context));
|
||||
*nss_context = NULL;
|
||||
}
|
||||
|
||||
|
||||
void back_extdom_set_timeout(struct nss_ops_ctx *nss_context,
|
||||
unsigned int timeout) {
|
||||
if (nss_context == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nss_context->timeout = timeout;
|
||||
}
|
||||
|
||||
void back_extdom_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 back_extdom_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 back_extdom_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 back_extdom_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 back_extdom_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 back_extdom_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 back_extdom_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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
dn: cn=ipa_extdom_extop,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: ipa_extdom_extop
|
||||
nsslapd-pluginpath: libipa_extdom_extop
|
||||
nsslapd-plugininitfunc: ipa_extdom_init
|
||||
nsslapd-plugintype: extendedop
|
||||
nsslapd-pluginenabled: on
|
||||
nsslapd-pluginid: ipa_extdom_extop
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: RedHat
|
||||
nsslapd-plugindescription: Support resolving IDs in trusted domains to names and back
|
||||
nsslapd-plugin-depends-on-type: database
|
||||
nsslapd-basedn: $SUFFIX
|
||||
209
daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
Normal file
209
daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
Normal file
@@ -0,0 +1,209 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* 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/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links to the code of this Program through those well
|
||||
* defined interfaces identified in the file named EXCEPTION found in
|
||||
* the source code files (the "Approved Interfaces"). The files of
|
||||
* Non-GPL Code may instantiate templates or use macros or inline
|
||||
* functions from the Approved Interfaces without causing the resulting
|
||||
* work to be covered by the GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Authors:
|
||||
* Sumit Bose <sbose@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <dirsrv/slapi-plugin.h>
|
||||
#include <lber.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sss_nss_idmap.h>
|
||||
|
||||
#define EXOP_EXTDOM_OID "2.16.840.1.113730.3.8.10.4"
|
||||
#define EXOP_EXTDOM_V1_OID "2.16.840.1.113730.3.8.10.4.1"
|
||||
|
||||
#define IPA_EXTDOM_PLUGIN_NAME "ipa-extdom-extop"
|
||||
#define IPA_EXTDOM_FEATURE_DESC "IPA trusted domain ID mapper"
|
||||
#define IPA_EXTDOM_PLUGIN_DESC "Support resolving IDs in trusted domains to names and back"
|
||||
|
||||
#define IPA_PLUGIN_NAME IPA_EXTDOM_PLUGIN_NAME
|
||||
|
||||
enum extdom_version {
|
||||
EXTDOM_V0 = 0,
|
||||
EXTDOM_V1
|
||||
};
|
||||
|
||||
enum input_types {
|
||||
INP_SID = 1,
|
||||
INP_NAME,
|
||||
INP_POSIX_UID,
|
||||
INP_POSIX_GID,
|
||||
INP_CERT
|
||||
};
|
||||
|
||||
enum request_types {
|
||||
REQ_SIMPLE = 1,
|
||||
REQ_FULL,
|
||||
REQ_FULL_WITH_GROUPS
|
||||
};
|
||||
|
||||
enum response_types {
|
||||
RESP_SID = 1,
|
||||
RESP_NAME,
|
||||
RESP_USER,
|
||||
RESP_GROUP,
|
||||
RESP_USER_GROUPLIST,
|
||||
RESP_GROUP_MEMBERS,
|
||||
RESP_NAME_LIST
|
||||
};
|
||||
|
||||
struct extdom_req {
|
||||
enum input_types input_type;
|
||||
enum request_types request_type;
|
||||
union {
|
||||
char *sid;
|
||||
struct {
|
||||
char *domain_name;
|
||||
char *object_name;
|
||||
} name;
|
||||
struct {
|
||||
char *domain_name;
|
||||
uid_t uid;
|
||||
} posix_uid;
|
||||
struct {
|
||||
char *domain_name;
|
||||
gid_t gid;
|
||||
} posix_gid;
|
||||
char *cert;
|
||||
} data;
|
||||
char *err_msg;
|
||||
};
|
||||
|
||||
struct extdom_res {
|
||||
enum response_types response_type;
|
||||
union {
|
||||
char *sid;
|
||||
struct {
|
||||
char *domain_name;
|
||||
char *object_name;
|
||||
} name;
|
||||
struct {
|
||||
char *domain_name;
|
||||
char *user_name;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char *gecos;
|
||||
char *home;
|
||||
char *shell;
|
||||
size_t ngroups;
|
||||
char **groups;
|
||||
} user;
|
||||
struct {
|
||||
char *domain_name;
|
||||
char *group_name;
|
||||
gid_t gid;
|
||||
size_t nmembers;
|
||||
char **members;
|
||||
} group;
|
||||
} data;
|
||||
};
|
||||
|
||||
struct nss_ops_ctx;
|
||||
|
||||
struct ipa_extdom_ctx {
|
||||
Slapi_ComponentId *plugin_id;
|
||||
char *base_dn;
|
||||
size_t max_nss_buf_size;
|
||||
struct nss_ops_ctx *nss_ctx;
|
||||
};
|
||||
|
||||
struct domain_info {
|
||||
char *flat_name;
|
||||
char *sid;
|
||||
char *guid;
|
||||
};
|
||||
|
||||
struct pwd_grp {
|
||||
enum sss_id_type id_type;
|
||||
union {
|
||||
struct passwd pwd;
|
||||
struct group grp;
|
||||
} data;
|
||||
int ngroups;
|
||||
gid_t *groups;
|
||||
};
|
||||
|
||||
int parse_request_data(struct berval *req_val, struct extdom_req **_req);
|
||||
void free_req_data(struct extdom_req *req);
|
||||
int check_request(struct extdom_req *req, enum extdom_version version);
|
||||
int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
|
||||
struct berval **berval);
|
||||
int pack_response(struct extdom_res *res, struct berval **ret_val);
|
||||
int get_buffer(size_t *_buf_len, char **_buf);
|
||||
int getpwnam_r_wrapper(struct ipa_extdom_ctx *ctx, const char *name,
|
||||
struct passwd *pwd, char **_buf, size_t *_buf_len);
|
||||
int getpwuid_r_wrapper(struct ipa_extdom_ctx *ctx, uid_t uid,
|
||||
struct passwd *pwd, char **_buf, size_t *_buf_len);
|
||||
int getgrnam_r_wrapper(struct ipa_extdom_ctx *ctx, const char *name,
|
||||
struct group *grp, char **_buf, size_t *_buf_len);
|
||||
int getgrgid_r_wrapper(struct ipa_extdom_ctx *ctx, gid_t gid,
|
||||
struct group *grp, char **_buf, size_t *_buf_len);
|
||||
int get_user_grouplist(struct ipa_extdom_ctx *ctx, const char *name, gid_t gid,
|
||||
size_t *_ngroups, gid_t **_groups);
|
||||
int pack_ber_sid(const char *sid, struct berval **berval);
|
||||
int pack_ber_name(const char *domain_name, const char *name,
|
||||
struct berval **berval);
|
||||
int pack_ber_user(struct ipa_extdom_ctx *ctx,
|
||||
enum response_types response_type,
|
||||
const char *domain_name, const char *user_name,
|
||||
uid_t uid, gid_t gid,
|
||||
const char *gecos, const char *homedir,
|
||||
const char *shell, struct sss_nss_kv *kv_list,
|
||||
struct berval **berval);
|
||||
int pack_ber_group(enum response_types response_type,
|
||||
const char *domain_name, const char *group_name,
|
||||
gid_t gid, char **members, struct sss_nss_kv *kv_list,
|
||||
struct berval **berval);
|
||||
void set_err_msg(struct extdom_req *req, const char *format, ...);
|
||||
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
Authors:
|
||||
Sumit Bose <sbose@redhat.com>
|
||||
|
||||
Copyright (C) 2015 Red Hat
|
||||
|
||||
Extdom tests
|
||||
|
||||
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/>.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
|
||||
#include "ipa_extdom.h"
|
||||
#include "back_extdom.h"
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define MAX_BUF (1024*1024*1024)
|
||||
struct test_data {
|
||||
struct extdom_req *req;
|
||||
struct ipa_extdom_ctx *ctx;
|
||||
};
|
||||
|
||||
/*
|
||||
* redefine logging for mocks
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 3, 4)))
|
||||
#endif
|
||||
int slapi_log_error(int loglevel, char *subsystem, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vprint_error(fmt, ap);
|
||||
va_end(ap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We cannot run cmocka tests against SSSD as that would require to set up SSSD
|
||||
* and the rest of environment. Instead, we compile cmocka tests against
|
||||
* back_extdom_nss_sss.c and re-define context initialization to use
|
||||
* nsswrapper with our test data.
|
||||
*
|
||||
* This means we have to keep struct nss_ops_ctx definition in sync with tests!
|
||||
*/
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
int cmocka_extdom_init_context(struct nss_ops_ctx **nss_context)
|
||||
{
|
||||
struct nss_ops_ctx *ctx = NULL;
|
||||
|
||||
if (nss_context == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx = calloc(1, sizeof(struct nss_ops_ctx));
|
||||
|
||||
if (ctx == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
*nss_context = ctx;
|
||||
|
||||
ctx->dl_handle = dlopen("libnss_files.so.2", RTLD_NOW);
|
||||
if (ctx->dl_handle == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_files_getpwnam_r");
|
||||
if (ctx->getpwnam_r == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_files_getpwuid_r");
|
||||
if (ctx->getpwuid_r == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_files_getgrnam_r");
|
||||
if (ctx->getgrnam_r == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_files_getgrgid_r");
|
||||
if (ctx->getgrgid_r == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_files_initgroups_dyn");
|
||||
if (ctx->initgroups_dyn == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
back_extdom_free_context(nss_context);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct {
|
||||
const char *o, *n;
|
||||
} path_table[] = {
|
||||
{ .o = "/etc/passwd", .n = "./test_data/passwd"},
|
||||
{ .o = "/etc/group", .n = "./test_data/group"},
|
||||
{ .o = NULL, .n = NULL}};
|
||||
|
||||
FILE *(*original_fopen)(const char*, const char*) = NULL;
|
||||
|
||||
FILE *fopen(const char *path, const char *mode) {
|
||||
const char *_path = NULL;
|
||||
|
||||
/* Do not handle before-main() cases */
|
||||
if (original_fopen == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for(int i=0; path_table[i].o != NULL; i++) {
|
||||
if (strcmp(path, path_table[i].o) == 0) {
|
||||
_path = path_table[i].n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (*original_fopen)(_path ? _path : path, mode);
|
||||
}
|
||||
|
||||
/* Attempt to initialize original_fopen before main()
|
||||
* There is no explicit order when all initializers are called,
|
||||
* so we might still be late here compared to a code in a shared
|
||||
* library initializer, like libselinux */
|
||||
void redefined_fopen_ctor (void) __attribute__ ((constructor));
|
||||
void redefined_fopen_ctor(void) {
|
||||
original_fopen = dlsym(RTLD_NEXT, "fopen");
|
||||
}
|
||||
|
||||
void test_getpwnam_r_wrapper(void **state)
|
||||
{
|
||||
int ret;
|
||||
struct passwd pwd;
|
||||
char *buf;
|
||||
size_t buf_len, max_big_buf_len;
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = (struct test_data *) *state;
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ret = getpwnam_r_wrapper(test_data->ctx,
|
||||
"non_exisiting_user", &pwd,
|
||||
&buf, &buf_len);
|
||||
assert_int_equal(ret, ENOENT);
|
||||
|
||||
ret = getpwnam_r_wrapper(test_data->ctx,
|
||||
"user", &pwd, &buf, &buf_len);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(pwd.pw_name, "user");
|
||||
assert_string_equal(pwd.pw_passwd, "x");
|
||||
assert_int_equal(pwd.pw_uid, 12345);
|
||||
assert_int_equal(pwd.pw_gid, 23456);
|
||||
assert_string_equal(pwd.pw_gecos, "gecos");
|
||||
assert_string_equal(pwd.pw_dir, "/home/user");
|
||||
assert_string_equal(pwd.pw_shell, "/bin/shell");
|
||||
free(buf);
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ret = getpwnam_r_wrapper(test_data->ctx,
|
||||
"user_big", &pwd, &buf, &buf_len);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(pwd.pw_name, "user_big");
|
||||
assert_string_equal(pwd.pw_passwd, "x");
|
||||
assert_int_equal(pwd.pw_uid, 12346);
|
||||
assert_int_equal(pwd.pw_gid, 23457);
|
||||
assert_int_equal(strlen(pwd.pw_gecos), 4000 * strlen("gecos"));
|
||||
assert_string_equal(pwd.pw_dir, "/home/user_big");
|
||||
assert_string_equal(pwd.pw_shell, "/bin/shell");
|
||||
free(buf);
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
max_big_buf_len = test_data->ctx->max_nss_buf_size;
|
||||
test_data->ctx->max_nss_buf_size = 1024;
|
||||
ret = getpwnam_r_wrapper(test_data->ctx,
|
||||
"user_big", &pwd, &buf, &buf_len);
|
||||
test_data->ctx->max_nss_buf_size = max_big_buf_len;
|
||||
assert_int_equal(ret, ERANGE);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void test_getpwuid_r_wrapper(void **state)
|
||||
{
|
||||
int ret;
|
||||
struct passwd pwd;
|
||||
char *buf;
|
||||
size_t buf_len, max_big_buf_len;
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = (struct test_data *) *state;
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ret = getpwuid_r_wrapper(test_data->ctx, 99999, &pwd, &buf, &buf_len);
|
||||
assert_int_equal(ret, ENOENT);
|
||||
|
||||
ret = getpwuid_r_wrapper(test_data->ctx, 12345, &pwd, &buf, &buf_len);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(pwd.pw_name, "user");
|
||||
assert_string_equal(pwd.pw_passwd, "x");
|
||||
assert_int_equal(pwd.pw_uid, 12345);
|
||||
assert_int_equal(pwd.pw_gid, 23456);
|
||||
assert_string_equal(pwd.pw_gecos, "gecos");
|
||||
assert_string_equal(pwd.pw_dir, "/home/user");
|
||||
assert_string_equal(pwd.pw_shell, "/bin/shell");
|
||||
free(buf);
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ret = getpwuid_r_wrapper(test_data->ctx, 12346, &pwd, &buf, &buf_len);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(pwd.pw_name, "user_big");
|
||||
assert_string_equal(pwd.pw_passwd, "x");
|
||||
assert_int_equal(pwd.pw_uid, 12346);
|
||||
assert_int_equal(pwd.pw_gid, 23457);
|
||||
assert_int_equal(strlen(pwd.pw_gecos), 4000 * strlen("gecos"));
|
||||
assert_string_equal(pwd.pw_dir, "/home/user_big");
|
||||
assert_string_equal(pwd.pw_shell, "/bin/shell");
|
||||
free(buf);
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
max_big_buf_len = test_data->ctx->max_nss_buf_size;
|
||||
test_data->ctx->max_nss_buf_size = 1024;
|
||||
ret = getpwuid_r_wrapper(test_data->ctx, 12346, &pwd, &buf, &buf_len);
|
||||
test_data->ctx->max_nss_buf_size = max_big_buf_len;
|
||||
assert_int_equal(ret, ERANGE);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void test_getgrnam_r_wrapper(void **state)
|
||||
{
|
||||
int ret;
|
||||
struct group grp;
|
||||
char *buf;
|
||||
size_t buf_len, max_big_buf_len;
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = (struct test_data *) *state;
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ret = getgrnam_r_wrapper(test_data->ctx,
|
||||
"non_exisiting_group", &grp, &buf, &buf_len);
|
||||
assert_int_equal(ret, ENOENT);
|
||||
|
||||
ret = getgrnam_r_wrapper(test_data->ctx, "group", &grp, &buf, &buf_len);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(grp.gr_name, "group");
|
||||
assert_string_equal(grp.gr_passwd, "x");
|
||||
assert_int_equal(grp.gr_gid, 11111);
|
||||
assert_string_equal(grp.gr_mem[0], "member0001");
|
||||
assert_string_equal(grp.gr_mem[1], "member0002");
|
||||
assert_null(grp.gr_mem[2]);
|
||||
free(buf);
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ret = getgrnam_r_wrapper(test_data->ctx, "group_big", &grp, &buf, &buf_len);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(grp.gr_name, "group_big");
|
||||
assert_string_equal(grp.gr_passwd, "x");
|
||||
assert_int_equal(grp.gr_gid, 22222);
|
||||
assert_string_equal(grp.gr_mem[0], "member0001");
|
||||
assert_string_equal(grp.gr_mem[1], "member0002");
|
||||
free(buf);
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
max_big_buf_len = test_data->ctx->max_nss_buf_size;
|
||||
test_data->ctx->max_nss_buf_size = 1024;
|
||||
ret = getgrnam_r_wrapper(test_data->ctx, "group_big", &grp, &buf, &buf_len);
|
||||
test_data->ctx->max_nss_buf_size = max_big_buf_len;
|
||||
assert_int_equal(ret, ERANGE);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void test_getgrgid_r_wrapper(void **state)
|
||||
{
|
||||
int ret;
|
||||
struct group grp;
|
||||
char *buf;
|
||||
size_t buf_len, max_big_buf_len;
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = (struct test_data *) *state;
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ret = getgrgid_r_wrapper(test_data->ctx, 99999, &grp, &buf, &buf_len);
|
||||
assert_int_equal(ret, ENOENT);
|
||||
|
||||
ret = getgrgid_r_wrapper(test_data->ctx, 11111, &grp, &buf, &buf_len);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(grp.gr_name, "group");
|
||||
assert_string_equal(grp.gr_passwd, "x");
|
||||
assert_int_equal(grp.gr_gid, 11111);
|
||||
assert_string_equal(grp.gr_mem[0], "member0001");
|
||||
assert_string_equal(grp.gr_mem[1], "member0002");
|
||||
assert_null(grp.gr_mem[2]);
|
||||
free(buf);
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
ret = getgrgid_r_wrapper(test_data->ctx, 22222, &grp, &buf, &buf_len);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(grp.gr_name, "group_big");
|
||||
assert_string_equal(grp.gr_passwd, "x");
|
||||
assert_int_equal(grp.gr_gid, 22222);
|
||||
assert_string_equal(grp.gr_mem[0], "member0001");
|
||||
assert_string_equal(grp.gr_mem[1], "member0002");
|
||||
free(buf);
|
||||
|
||||
ret = get_buffer(&buf_len, &buf);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
max_big_buf_len = test_data->ctx->max_nss_buf_size;
|
||||
test_data->ctx->max_nss_buf_size = 1024;
|
||||
ret = getgrgid_r_wrapper(test_data->ctx, 22222, &grp, &buf, &buf_len);
|
||||
test_data->ctx->max_nss_buf_size = max_big_buf_len;
|
||||
assert_int_equal(ret, ERANGE);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void test_get_user_grouplist(void **state)
|
||||
{
|
||||
int ret;
|
||||
size_t ngroups;
|
||||
gid_t *groups;
|
||||
size_t c;
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = (struct test_data *) *state;
|
||||
|
||||
/* This is a bit odd behaviour of getgrouplist() it does not check if the
|
||||
* user exists, only if memberships of the user can be found. */
|
||||
ret = get_user_grouplist(test_data->ctx,
|
||||
"non_exisiting_user", 23456, &ngroups, &groups);
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(ngroups, 1);
|
||||
assert_int_equal(groups[0], 23456);
|
||||
free(groups);
|
||||
|
||||
ret = get_user_grouplist(test_data->ctx,
|
||||
"member0001", 23456, &ngroups, &groups);
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(ngroups, 3);
|
||||
assert_int_equal(groups[0], 23456);
|
||||
assert_int_equal(groups[1], 11111);
|
||||
assert_int_equal(groups[2], 22222);
|
||||
free(groups);
|
||||
|
||||
ret = get_user_grouplist(test_data->ctx,
|
||||
"member0003", 23456, &ngroups, &groups);
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(ngroups, 2);
|
||||
assert_int_equal(groups[0], 23456);
|
||||
assert_int_equal(groups[1], 22222);
|
||||
free(groups);
|
||||
|
||||
ret = get_user_grouplist(test_data->ctx,
|
||||
"user_big", 23456, &ngroups, &groups);
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(ngroups, 1001);
|
||||
assert_int_equal(groups[0], 23456);
|
||||
for (c = 1; c < ngroups; c++) {
|
||||
assert_int_equal(groups[c], 29999 + c);
|
||||
}
|
||||
free(groups);
|
||||
}
|
||||
|
||||
static int extdom_req_setup(void **state)
|
||||
{
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = calloc(sizeof(struct test_data), 1);
|
||||
assert_non_null(test_data);
|
||||
|
||||
test_data->req = calloc(sizeof(struct extdom_req), 1);
|
||||
assert_non_null(test_data->req);
|
||||
|
||||
test_data->ctx = calloc(sizeof(struct ipa_extdom_ctx), 1);
|
||||
assert_non_null(test_data->ctx);
|
||||
|
||||
test_data->ctx->max_nss_buf_size = MAX_BUF;
|
||||
|
||||
assert_int_equal(cmocka_extdom_init_context(&test_data->ctx->nss_ctx), 0);
|
||||
assert_non_null(test_data->ctx->nss_ctx);
|
||||
|
||||
back_extdom_set_timeout(test_data->ctx->nss_ctx, 10000);
|
||||
*state = test_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extdom_req_teardown(void **state)
|
||||
{
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = (struct test_data *) *state;
|
||||
|
||||
free_req_data(test_data->req);
|
||||
back_extdom_free_context(&test_data->ctx->nss_ctx);
|
||||
free(test_data->ctx);
|
||||
free(test_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_set_err_msg(void **state)
|
||||
{
|
||||
struct extdom_req *req;
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = (struct test_data *) *state;
|
||||
req = test_data->req;
|
||||
|
||||
assert_null(req->err_msg);
|
||||
|
||||
set_err_msg(NULL, NULL);
|
||||
assert_null(req->err_msg);
|
||||
|
||||
set_err_msg(req, NULL);
|
||||
assert_null(req->err_msg);
|
||||
|
||||
set_err_msg(req, "Test [%s][%d].", "ABCD", 1234);
|
||||
assert_non_null(req->err_msg);
|
||||
assert_string_equal(req->err_msg, "Test [ABCD][1234].");
|
||||
|
||||
set_err_msg(req, "2nd Test [%s][%d].", "ABCD", 1234);
|
||||
assert_non_null(req->err_msg);
|
||||
assert_string_equal(req->err_msg, "Test [ABCD][1234].");
|
||||
}
|
||||
|
||||
#define TEST_SID "S-1-2-3-4"
|
||||
#define TEST_DOMAIN_NAME "DOMAIN"
|
||||
|
||||
char res_sid[] = {0x30, 0x0e, 0x0a, 0x01, 0x01, 0x04, 0x09, 0x53, 0x2d, 0x31, \
|
||||
0x2d, 0x32, 0x2d, 0x33, 0x2d, 0x34};
|
||||
char res_nam[] = {0x30, 0x13, 0x0a, 0x01, 0x02, 0x30, 0x0e, 0x04, 0x06, 0x44, \
|
||||
0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x04, 0x04, 0x74, 0x65, 0x73, \
|
||||
0x74};
|
||||
char res_uid[] = {0x30, 0x1c, 0x0a, 0x01, 0x03, 0x30, 0x17, 0x04, 0x06, 0x44, \
|
||||
0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x04, 0x04, 0x74, 0x65, 0x73, \
|
||||
0x74, 0x02, 0x02, 0x30, 0x39, 0x02, 0x03, 0x00, 0xd4, 0x31};
|
||||
char res_gid[] = {0x30, 0x1e, 0x0a, 0x01, 0x04, 0x30, 0x19, 0x04, 0x06, 0x44, \
|
||||
0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x04, 0x0a, 0x74, 0x65, 0x73, \
|
||||
0x74, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x02, 0x03, 0x00, \
|
||||
0xd4, 0x31};
|
||||
|
||||
void test_encode(void **state)
|
||||
{
|
||||
int ret;
|
||||
struct berval *resp_val;
|
||||
struct ipa_extdom_ctx *ctx;
|
||||
struct test_data *test_data;
|
||||
|
||||
test_data = (struct test_data *) *state;
|
||||
ctx = test_data->ctx;
|
||||
|
||||
ctx->max_nss_buf_size = (128*1024*1024);
|
||||
|
||||
ret = pack_ber_sid(TEST_SID, &resp_val);
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(sizeof(res_sid), resp_val->bv_len);
|
||||
assert_memory_equal(res_sid, resp_val->bv_val, resp_val->bv_len);
|
||||
ber_bvfree(resp_val);
|
||||
|
||||
ret = pack_ber_name(TEST_DOMAIN_NAME, "test", &resp_val);
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(sizeof(res_nam), resp_val->bv_len);
|
||||
assert_memory_equal(res_nam, resp_val->bv_val, resp_val->bv_len);
|
||||
ber_bvfree(resp_val);
|
||||
|
||||
ret = pack_ber_user(ctx, RESP_USER, TEST_DOMAIN_NAME, "test", 12345, 54321,
|
||||
NULL, NULL, NULL, NULL, &resp_val);
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(sizeof(res_uid), resp_val->bv_len);
|
||||
assert_memory_equal(res_uid, resp_val->bv_val, resp_val->bv_len);
|
||||
ber_bvfree(resp_val);
|
||||
|
||||
ret = pack_ber_group(RESP_GROUP, TEST_DOMAIN_NAME, "test_group", 54321,
|
||||
NULL, NULL, &resp_val);
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(sizeof(res_gid), resp_val->bv_len);
|
||||
assert_memory_equal(res_gid, resp_val->bv_val, resp_val->bv_len);
|
||||
ber_bvfree(resp_val);
|
||||
}
|
||||
|
||||
char req_sid[] = {0x30, 0x11, 0x0a, 0x01, 0x01, 0x0a, 0x01, 0x01, 0x04, 0x09, \
|
||||
0x53, 0x2d, 0x31, 0x2d, 0x32, 0x2d, 0x33, 0x2d, 0x34};
|
||||
char req_nam[] = {0x30, 0x16, 0x0a, 0x01, 0x02, 0x0a, 0x01, 0x01, 0x30, 0x0e, \
|
||||
0x04, 0x06, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x04, 0x04, \
|
||||
0x74, 0x65, 0x73, 0x74};
|
||||
char req_uid[] = {0x30, 0x14, 0x0a, 0x01, 0x03, 0x0a, 0x01, 0x01, 0x30, 0x0c, \
|
||||
0x04, 0x06, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x02, 0x02, \
|
||||
0x30, 0x39};
|
||||
char req_gid[] = {0x30, 0x15, 0x0a, 0x01, 0x04, 0x0a, 0x01, 0x01, 0x30, 0x0d, \
|
||||
0x04, 0x06, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x02, 0x03, \
|
||||
0x00, 0xd4, 0x31};
|
||||
|
||||
void test_decode(void **state)
|
||||
{
|
||||
struct berval req_val;
|
||||
struct extdom_req *req;
|
||||
int ret;
|
||||
|
||||
req_val.bv_val = req_sid;
|
||||
req_val.bv_len = sizeof(req_sid);
|
||||
|
||||
ret = parse_request_data(&req_val, &req);
|
||||
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(req->input_type, INP_SID);
|
||||
assert_int_equal(req->request_type, REQ_SIMPLE);
|
||||
assert_string_equal(req->data.sid, "S-1-2-3-4");
|
||||
free_req_data(req);
|
||||
|
||||
req_val.bv_val = req_nam;
|
||||
req_val.bv_len = sizeof(req_nam);
|
||||
|
||||
ret = parse_request_data(&req_val, &req);
|
||||
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(req->input_type, INP_NAME);
|
||||
assert_int_equal(req->request_type, REQ_SIMPLE);
|
||||
assert_string_equal(req->data.name.domain_name, "DOMAIN");
|
||||
assert_string_equal(req->data.name.object_name, "test");
|
||||
free_req_data(req);
|
||||
|
||||
req_val.bv_val = req_uid;
|
||||
req_val.bv_len = sizeof(req_uid);
|
||||
|
||||
ret = parse_request_data(&req_val, &req);
|
||||
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(req->input_type, INP_POSIX_UID);
|
||||
assert_int_equal(req->request_type, REQ_SIMPLE);
|
||||
assert_string_equal(req->data.posix_uid.domain_name, "DOMAIN");
|
||||
assert_int_equal(req->data.posix_uid.uid, 12345);
|
||||
free_req_data(req);
|
||||
|
||||
req_val.bv_val = req_gid;
|
||||
req_val.bv_len = sizeof(req_gid);
|
||||
|
||||
ret = parse_request_data(&req_val, &req);
|
||||
|
||||
assert_int_equal(ret, LDAP_SUCCESS);
|
||||
assert_int_equal(req->input_type, INP_POSIX_GID);
|
||||
assert_int_equal(req->request_type, REQ_SIMPLE);
|
||||
assert_string_equal(req->data.posix_gid.domain_name, "DOMAIN");
|
||||
assert_int_equal(req->data.posix_gid.gid, 54321);
|
||||
free_req_data(req);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(test_getpwnam_r_wrapper),
|
||||
cmocka_unit_test(test_getpwuid_r_wrapper),
|
||||
cmocka_unit_test(test_getgrnam_r_wrapper),
|
||||
cmocka_unit_test(test_getgrgid_r_wrapper),
|
||||
cmocka_unit_test(test_get_user_grouplist),
|
||||
cmocka_unit_test_setup_teardown(test_set_err_msg,
|
||||
extdom_req_setup, extdom_req_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_encode,
|
||||
extdom_req_setup, extdom_req_teardown),
|
||||
cmocka_unit_test(test_decode),
|
||||
};
|
||||
|
||||
assert_non_null(original_fopen);
|
||||
return cmocka_run_group_tests(tests, extdom_req_setup, extdom_req_teardown);
|
||||
}
|
||||
1385
daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
Normal file
1385
daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
Normal file
File diff suppressed because it is too large
Load Diff
275
daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
Normal file
275
daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* 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/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links to the code of this Program through those well
|
||||
* defined interfaces identified in the file named EXCEPTION found in
|
||||
* the source code files (the "Approved Interfaces"). The files of
|
||||
* Non-GPL Code may instantiate templates or use macros or inline
|
||||
* functions from the Approved Interfaces without causing the resulting
|
||||
* work to be covered by the GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Authors:
|
||||
* Sumit Bose <sbose@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
#include "ipa_extdom.h"
|
||||
#include "back_extdom.h"
|
||||
#include "util.h"
|
||||
|
||||
#define DEFAULT_MAX_NSS_BUFFER (128*1024*1024)
|
||||
#define DEFAULT_MAX_NSS_TIMEOUT (10*1000)
|
||||
|
||||
Slapi_PluginDesc ipa_extdom_plugin_desc = {
|
||||
IPA_EXTDOM_FEATURE_DESC,
|
||||
"FreeIPA project",
|
||||
"FreeIPA/1.0",
|
||||
IPA_EXTDOM_PLUGIN_DESC
|
||||
};
|
||||
|
||||
static char *ipa_extdom_oid_list[] = {
|
||||
EXOP_EXTDOM_OID,
|
||||
EXOP_EXTDOM_V1_OID,
|
||||
NULL
|
||||
};
|
||||
|
||||
static char *ipa_extdom_name_list[] = {
|
||||
IPA_EXTDOM_PLUGIN_DESC,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ipa_extdom_start(Slapi_PBlock *pb)
|
||||
{
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
static int ipa_extdom_extop(Slapi_PBlock *pb)
|
||||
{
|
||||
char *oid = NULL;
|
||||
char *err_msg = NULL;
|
||||
int rc;
|
||||
int ret;
|
||||
struct berval *req_val = NULL;
|
||||
struct berval *ret_val = NULL;
|
||||
struct extdom_req *req = NULL;
|
||||
struct ipa_extdom_ctx *ctx;
|
||||
enum extdom_version version;
|
||||
|
||||
ret = slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &oid);
|
||||
if (ret != 0) {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
err_msg = "Could not get OID value from request.\n";
|
||||
goto done;
|
||||
}
|
||||
LOG("Received extended operation request with OID %s\n", oid);
|
||||
|
||||
if (strcasecmp(oid, EXOP_EXTDOM_OID) == 0) {
|
||||
version = EXTDOM_V0;
|
||||
} else if (strcasecmp(oid, EXOP_EXTDOM_V1_OID) == 0) {
|
||||
version = EXTDOM_V1;
|
||||
} else {
|
||||
return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
|
||||
}
|
||||
|
||||
ret = slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &req_val);
|
||||
if (ret != 0) {
|
||||
rc = LDAP_UNWILLING_TO_PERFORM;
|
||||
err_msg = "Missing request data.\n";
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &ctx);
|
||||
if (ret != 0) {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
err_msg = "Missing plugin context.\n";
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = parse_request_data(req_val, &req);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
rc = LDAP_UNWILLING_TO_PERFORM;
|
||||
err_msg = "Cannot parse request data.\n";
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = check_request(req, version);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
rc = LDAP_UNWILLING_TO_PERFORM;
|
||||
err_msg = "Error in request data.\n";
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = handle_request(ctx, req, &ret_val);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
if (ret == LDAP_NO_SUCH_OBJECT) {
|
||||
rc = LDAP_NO_SUCH_OBJECT;
|
||||
} else {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
err_msg = "Failed to handle the request.\n";
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, oid);
|
||||
if (ret != 0) {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
err_msg = "Failed to set the OID for the response.\n";
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = slapi_pblock_set( pb, SLAPI_EXT_OP_RET_VALUE, ret_val);
|
||||
if (ret != 0) {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
err_msg = "Failed to set the value for the response.\n";
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = LDAP_SUCCESS;
|
||||
|
||||
done:
|
||||
if ((req != NULL) && (req->err_msg != NULL)) {
|
||||
err_msg = req->err_msg;
|
||||
}
|
||||
if (err_msg != NULL) {
|
||||
LOG("%s", err_msg);
|
||||
}
|
||||
slapi_send_ldap_result(pb, rc, NULL, err_msg, 0, NULL);
|
||||
ber_bvfree(ret_val);
|
||||
free_req_data(req);
|
||||
return SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
|
||||
}
|
||||
|
||||
static int ipa_extdom_init_ctx(Slapi_PBlock *pb, struct ipa_extdom_ctx **_ctx)
|
||||
{
|
||||
struct ipa_extdom_ctx *ctx;
|
||||
Slapi_Entry *e;
|
||||
int ret;
|
||||
unsigned int timeout;
|
||||
|
||||
ctx = calloc(1, sizeof(struct ipa_extdom_ctx));
|
||||
if (!ctx) {
|
||||
return LDAP_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
ret = slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &ctx->plugin_id);
|
||||
if ((ret != 0) || (NULL == ctx->plugin_id)) {
|
||||
LOG_FATAL("Could not get identity or identity was NULL\n");
|
||||
if (ret == 0) {
|
||||
ret = -1;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &e);
|
||||
if (!e) {
|
||||
LOG_FATAL("Plugin configuration not found!\n");
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctx->base_dn = slapi_entry_attr_get_charptr(e, "nsslapd-basedn");
|
||||
if (!ctx->base_dn) {
|
||||
LOG_FATAL("Base DN not found in plugin configuration not found!\n");
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctx->max_nss_buf_size = slapi_entry_attr_get_uint(e,
|
||||
"ipaExtdomMaxNssBufSize");
|
||||
if (ctx->max_nss_buf_size == 0) {
|
||||
ctx->max_nss_buf_size = DEFAULT_MAX_NSS_BUFFER;
|
||||
}
|
||||
LOG("Maximal nss buffer size set to [%zu]!\n", ctx->max_nss_buf_size);
|
||||
|
||||
|
||||
ret = back_extdom_init_context(&ctx->nss_ctx);
|
||||
if (ret != 0) {
|
||||
LOG("Unable to initialize nss interface: returned [%d]!\n", ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
timeout = slapi_entry_attr_get_uint(e, "ipaExtdomMaxNssTimeout");
|
||||
if (timeout == 0) {
|
||||
timeout = DEFAULT_MAX_NSS_TIMEOUT;
|
||||
}
|
||||
back_extdom_set_timeout(ctx->nss_ctx, timeout);
|
||||
LOG("Maximal nss timeout (in ms) set to [%u]!\n", timeout);
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
if (ret) {
|
||||
free(ctx);
|
||||
} else {
|
||||
*_ctx = ctx;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ipa_extdom_init(Slapi_PBlock *pb)
|
||||
{
|
||||
int ret;
|
||||
struct ipa_extdom_ctx *extdom_ctx;
|
||||
|
||||
ret = ipa_extdom_init_ctx(pb, &extdom_ctx);
|
||||
if (ret) {
|
||||
LOG_FATAL("Failed ot initialize external domain extended operation.\n");
|
||||
/* do not cause DS to stop, simply do nothing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
|
||||
if (!ret) {
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
|
||||
(void *)&ipa_extdom_plugin_desc);
|
||||
}
|
||||
if (!ret) {
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
|
||||
(void *)ipa_extdom_start);
|
||||
}
|
||||
if (!ret) {
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_OIDLIST,
|
||||
ipa_extdom_oid_list);
|
||||
}
|
||||
if (!ret) {
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_NAMELIST,
|
||||
ipa_extdom_name_list);
|
||||
}
|
||||
if (!ret) {
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_FN,
|
||||
(void *)ipa_extdom_extop);
|
||||
}
|
||||
if (!ret) {
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, extdom_ctx);
|
||||
}
|
||||
if (ret) {
|
||||
LOG("Failed to set plug-in version, function, and OID.\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1002
daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/group
Normal file
1002
daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/group
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user