diff options
Diffstat (limited to '')
-rw-r--r-- | servers/slapd/slapi/Makefile.in | 51 | ||||
-rw-r--r-- | servers/slapd/slapi/TODO | 16 | ||||
-rw-r--r-- | servers/slapd/slapi/plugin.c | 747 | ||||
-rw-r--r-- | servers/slapd/slapi/printmsg.c | 100 | ||||
-rw-r--r-- | servers/slapd/slapi/proto-slapi.h | 91 | ||||
-rw-r--r-- | servers/slapd/slapi/slapi.h | 204 | ||||
-rw-r--r-- | servers/slapd/slapi/slapi_dn.c | 669 | ||||
-rw-r--r-- | servers/slapd/slapi/slapi_ext.c | 349 | ||||
-rw-r--r-- | servers/slapd/slapi/slapi_ops.c | 956 | ||||
-rw-r--r-- | servers/slapd/slapi/slapi_overlay.c | 952 | ||||
-rw-r--r-- | servers/slapd/slapi/slapi_pblock.c | 1426 | ||||
-rw-r--r-- | servers/slapd/slapi/slapi_utils.c | 3473 | ||||
-rw-r--r-- | servers/slapd/slapindex.c | 110 |
13 files changed, 9144 insertions, 0 deletions
diff --git a/servers/slapd/slapi/Makefile.in b/servers/slapd/slapi/Makefile.in new file mode 100644 index 0000000..daf4f4f --- /dev/null +++ b/servers/slapd/slapi/Makefile.in @@ -0,0 +1,51 @@ +# Makefile.in for SLAPI +# $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 1998-2021 The OpenLDAP Foundation. +## Portions Copyright IBM Corp. 1997,2002,2003 +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. + +LIBRARY = libslapi.la + +#all-common: $(LIBRARY) $(PROGRAMS) +# @touch plugin.c slapi_pblock.c slapi_utils.c slapi_ops.c slapi_ext.c + +NT_SRCS = nt_err.c +NT_OBJS = nt_err.lo + +LIB_DEFS = -DSLAPI_LIBRARY + +SRCS= plugin.c slapi_pblock.c slapi_utils.c printmsg.c slapi_ops.c slapi_dn.c slapi_ext.c slapi_overlay.c \ + $(@PLAT@_SRCS) +OBJS= plugin.lo slapi_pblock.lo slapi_utils.lo printmsg.lo slapi_ops.lo slapi_dn.lo slapi_ext.lo slapi_overlay.lo \ + $(@PLAT@_SRCS) + +XSRCS= version.c + +LDAP_INCDIR= ../../../include -I.. -I. +LDAP_LIBDIR= ../../../libraries + +XLIBS = $(LIBRARY) +XXLIBS = +NT_LINK_LIBS = $(AC_LIBS) + +XINCPATH = -I$(srcdir)/.. -I$(srcdir) +XDEFS = $(MODULES_CPPFLAGS) + +BUILD_MOD = @BUILD_SLAPI@ + +install-local: FORCE + if test "$(BUILD_MOD)" = "yes"; then \ + $(MKDIR) $(DESTDIR)$(libdir); \ + $(LTINSTALL) $(INSTALLFLAGS) -m 644 $(LIBRARY) $(DESTDIR)$(libdir); \ + fi + diff --git a/servers/slapd/slapi/TODO b/servers/slapd/slapi/TODO new file mode 100644 index 0000000..8916488 --- /dev/null +++ b/servers/slapd/slapi/TODO @@ -0,0 +1,16 @@ +- de-IBM SLAPI +- add a config statement, or redefine the dynamic backend one, + "modulepath", to set/modify the load path also for plugins + (both plugins and modules use ltdl, so "modulepath" suffices ...) +- improve slapi logging (use some [v]s[n]printf function) +- add a config statement to set the log file name, or better +- use syslog where available? +- add some plugin monitoring stuff in back-monitor (e.g. a subentry + for each plugin with data from struct Slapi_PluginDesc) +- This is a very tough task: try to implement a sandbox to execute + plugins in, trap deadly signals and possibly disable unsafe plugins + without crashing slapd (fork from inside thread? trap signals + and longjump to next plugin execution? Brrr). + +--- +$OpenLDAP$ diff --git a/servers/slapd/slapi/plugin.c b/servers/slapd/slapi/plugin.c new file mode 100644 index 0000000..506f427 --- /dev/null +++ b/servers/slapd/slapi/plugin.c @@ -0,0 +1,747 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2002-2021 The OpenLDAP Foundation. + * Portions Copyright 1997,2002-2003 IBM Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by IBM Corporation for use in + * IBM products and subsequently ported to OpenLDAP Software by + * Steve Omrani. Additional significant contributors include: + * Luke Howard + */ + +#include "portable.h" +#include "ldap_pvt_thread.h" +#include "slap.h" +#include "config.h" +#include "slapi.h" +#include "lutil.h" + +/* + * Note: if ltdl.h is not available, slapi should not be compiled + */ +#include <ltdl.h> + +static int slapi_int_load_plugin( Slapi_PBlock *, const char *, const char *, int, + SLAPI_FUNC *, lt_dlhandle * ); + +/* pointer to link list of extended objects */ +static ExtendedOp *pGExtendedOps = NULL; + +/********************************************************************* + * Function Name: plugin_pblock_new + * + * Description: This routine creates a new Slapi_PBlock structure, + * loads in the plugin module and executes the init + * function provided by the module. + * + * Input: type - type of the plugin, such as SASL, database, etc. + * path - the loadpath to load the module in + * initfunc - name of the plugin function to execute first + * argc - number of arguements + * argv[] - an array of char pointers point to + * the arguments passed in via + * the configuration file. + * + * Output: + * + * Return Values: a pointer to a newly created Slapi_PBlock structrue or + * NULL - function failed + * + * Messages: None + *********************************************************************/ + +static Slapi_PBlock * +plugin_pblock_new( + int type, + int argc, + char *argv[] ) +{ + Slapi_PBlock *pPlugin = NULL; + Slapi_PluginDesc *pPluginDesc = NULL; + lt_dlhandle hdLoadHandle; + int rc; + char **av2 = NULL, **ppPluginArgv; + char *path = argv[2]; + char *initfunc = argv[3]; + + pPlugin = slapi_pblock_new(); + if ( pPlugin == NULL ) { + rc = LDAP_NO_MEMORY; + goto done; + } + + slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type ); + slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)&argc ); + + av2 = ldap_charray_dup( argv ); + if ( av2 == NULL ) { + rc = LDAP_NO_MEMORY; + goto done; + } + + if ( argc > 0 ) { + ppPluginArgv = &av2[4]; + } else { + ppPluginArgv = NULL; + } + + slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv ); + slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 ); + + rc = slapi_int_load_plugin( pPlugin, path, initfunc, 1, NULL, &hdLoadHandle ); + if ( rc != 0 ) { + goto done; + } + + if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 && + pPluginDesc != NULL ) { + slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new", + "Registered plugin %s %s [%s] (%s)\n", + pPluginDesc->spd_id, + pPluginDesc->spd_version, + pPluginDesc->spd_vendor, + pPluginDesc->spd_description); + } + +done: + if ( rc != 0 && pPlugin != NULL ) { + slapi_pblock_destroy( pPlugin ); + pPlugin = NULL; + if ( av2 != NULL ) { + ldap_charray_free( av2 ); + } + } + + return pPlugin; +} + +/********************************************************************* + * Function Name: slapi_int_register_plugin + * + * Description: insert the slapi_pblock structure to the end of the plugin + * list + * + * Input: a pointer to a plugin slapi_pblock structure to be added to + * the list + * + * Output: none + * + * Return Values: LDAP_SUCCESS - successfully inserted. + * LDAP_LOCAL_ERROR. + * + * Messages: None + *********************************************************************/ +int +slapi_int_register_plugin( + Backend *be, + Slapi_PBlock *pPB ) +{ + Slapi_PBlock *pTmpPB; + Slapi_PBlock *pSavePB; + int rc = LDAP_SUCCESS; + + assert( be != NULL ); + + pTmpPB = SLAPI_BACKEND_PBLOCK( be ); + if ( pTmpPB == NULL ) { + SLAPI_BACKEND_PBLOCK( be ) = pPB; + } else { + while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) { + pSavePB = pTmpPB; + rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB ); + } + + if ( rc == LDAP_SUCCESS ) { + rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK, (void *)pPB ); + } + } + + return ( rc != LDAP_SUCCESS ) ? LDAP_OTHER : LDAP_SUCCESS; +} + +/********************************************************************* + * Function Name: slapi_int_get_plugins + * + * Description: get the desired type of function pointers defined + * in all the plugins + * + * Input: the type of the functions to get, such as pre-operation,etc. + * + * Output: none + * + * Return Values: this routine returns a pointer to an array of function + * pointers containing backend-specific plugin functions + * followed by global plugin functions + * + * Messages: None + *********************************************************************/ +int +slapi_int_get_plugins( + Backend *be, + int functype, + SLAPI_FUNC **ppFuncPtrs ) +{ + + Slapi_PBlock *pCurrentPB; + SLAPI_FUNC FuncPtr; + SLAPI_FUNC *pTmpFuncPtr; + int numPB = 0; + int rc = LDAP_SUCCESS; + + assert( ppFuncPtrs != NULL ); + + if ( be == NULL ) { + goto done; + } + + pCurrentPB = SLAPI_BACKEND_PBLOCK( be ); + + while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) { + rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr ); + if ( rc == LDAP_SUCCESS ) { + if ( FuncPtr != NULL ) { + numPB++; + } + rc = slapi_pblock_get( pCurrentPB, + SLAPI_IBM_PBLOCK, &pCurrentPB ); + } + } + + if ( numPB == 0 ) { + *ppFuncPtrs = NULL; + rc = LDAP_SUCCESS; + goto done; + } + + /* + * Now, build the function pointer array of backend-specific + * plugins followed by global plugins. + */ + *ppFuncPtrs = pTmpFuncPtr = + (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) ); + if ( ppFuncPtrs == NULL ) { + rc = LDAP_NO_MEMORY; + goto done; + } + + pCurrentPB = SLAPI_BACKEND_PBLOCK( be ); + + while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) { + rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr ); + if ( rc == LDAP_SUCCESS ) { + if ( FuncPtr != NULL ) { + *pTmpFuncPtr = FuncPtr; + pTmpFuncPtr++; + } + rc = slapi_pblock_get( pCurrentPB, + SLAPI_IBM_PBLOCK, &pCurrentPB ); + } + } + + *pTmpFuncPtr = NULL; + + +done: + if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) { + ch_free( *ppFuncPtrs ); + *ppFuncPtrs = NULL; + } + + return rc; +} + +/********************************************************************* + * Function Name: createExtendedOp + * + * Description: Creates an extended operation structure and + * initializes the fields + * + * Return value: A newly allocated structure or NULL + ********************************************************************/ +ExtendedOp * +createExtendedOp() +{ + ExtendedOp *ret; + + ret = (ExtendedOp *)slapi_ch_malloc(sizeof(ExtendedOp)); + ret->ext_oid.bv_val = NULL; + ret->ext_oid.bv_len = 0; + ret->ext_func = NULL; + ret->ext_be = NULL; + ret->ext_next = NULL; + + return ret; +} + + +/********************************************************************* + * Function Name: slapi_int_unregister_extop + * + * Description: This routine removes the ExtendedOp structures + * asscoiated with a particular extended operation + * plugin. + * + * Input: pBE - pointer to a backend structure + * opList - pointer to a linked list of extended + * operation structures + * pPB - pointer to a slapi parameter block + * + * Output: + * + * Return Value: none + * + * Messages: None + *********************************************************************/ +void +slapi_int_unregister_extop( + Backend *pBE, + ExtendedOp **opList, + Slapi_PBlock *pPB ) +{ + ExtendedOp *pTmpExtOp, *backExtOp; + char **pTmpOIDs; + int i; + +#if 0 + assert( pBE != NULL); /* unused */ +#endif /* 0 */ + assert( opList != NULL ); + assert( pPB != NULL ); + + if ( *opList == NULL ) { + return; + } + + slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs ); + if ( pTmpOIDs == NULL ) { + return; + } + + for ( i = 0; pTmpOIDs[i] != NULL; i++ ) { + backExtOp = NULL; + pTmpExtOp = *opList; + for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) { + int rc; + rc = strcasecmp( pTmpExtOp->ext_oid.bv_val, + pTmpOIDs[ i ] ); + if ( rc == 0 ) { + if ( backExtOp == NULL ) { + *opList = pTmpExtOp->ext_next; + } else { + backExtOp->ext_next + = pTmpExtOp->ext_next; + } + + ch_free( pTmpExtOp ); + break; + } + backExtOp = pTmpExtOp; + } + } +} + + +/********************************************************************* + * Function Name: slapi_int_register_extop + * + * Description: This routine creates a new ExtendedOp structure, loads + * in the extended op module and put the extended op function address + * in the structure. The function will not be executed in + * this routine. + * + * Input: pBE - pointer to a backend structure + * opList - pointer to a linked list of extended + * operation structures + * pPB - pointer to a slapi parameter block + * + * Output: + * + * Return Value: an LDAP return code + * + * Messages: None + *********************************************************************/ +int +slapi_int_register_extop( + Backend *pBE, + ExtendedOp **opList, + Slapi_PBlock *pPB ) +{ + ExtendedOp *pTmpExtOp = NULL; + SLAPI_FUNC tmpFunc; + char **pTmpOIDs; + int rc = LDAP_OTHER; + int i; + + if ( (*opList) == NULL ) { + *opList = createExtendedOp(); + if ( (*opList) == NULL ) { + rc = LDAP_NO_MEMORY; + goto error_return; + } + pTmpExtOp = *opList; + + } else { /* Find the end of the list */ + for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL; + pTmpExtOp = pTmpExtOp->ext_next ) + ; /* EMPTY */ + pTmpExtOp->ext_next = createExtendedOp(); + if ( pTmpExtOp->ext_next == NULL ) { + rc = LDAP_NO_MEMORY; + goto error_return; + } + pTmpExtOp = pTmpExtOp->ext_next; + } + + rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs ); + if ( rc != 0 ) { + rc = LDAP_OTHER; + goto error_return; + } + + rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc); + if ( rc != 0 ) { + rc = LDAP_OTHER; + goto error_return; + } + + if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) { + rc = LDAP_OTHER; + goto error_return; + } + + for ( i = 0; pTmpOIDs[i] != NULL; i++ ) { + pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i]; + pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] ); + pTmpExtOp->ext_func = tmpFunc; + pTmpExtOp->ext_be = pBE; + if ( pTmpOIDs[i + 1] != NULL ) { + pTmpExtOp->ext_next = createExtendedOp(); + if ( pTmpExtOp->ext_next == NULL ) { + rc = LDAP_NO_MEMORY; + break; + } + pTmpExtOp = pTmpExtOp->ext_next; + } + } + +error_return: + return rc; +} + +/********************************************************************* + * Function Name: slapi_int_get_extop_plugin + * + * Description: This routine gets the function address for a given function + * name. + * + * Input: + * funcName - name of the extended op function, ie. an OID. + * + * Output: pFuncAddr - the function address of the requested function name. + * + * Return Values: a pointer to a newly created ExtendOp structrue or + * NULL - function failed + * + * Messages: None + *********************************************************************/ +int +slapi_int_get_extop_plugin( + struct berval *reqoid, + SLAPI_FUNC *pFuncAddr ) +{ + ExtendedOp *pTmpExtOp; + + assert( reqoid != NULL ); + assert( pFuncAddr != NULL ); + + *pFuncAddr = NULL; + + if ( pGExtendedOps == NULL ) { + return LDAP_OTHER; + } + + pTmpExtOp = pGExtendedOps; + while ( pTmpExtOp != NULL ) { + int rc; + + rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val ); + if ( rc == 0 ) { + *pFuncAddr = pTmpExtOp->ext_func; + break; + } + pTmpExtOp = pTmpExtOp->ext_next; + } + + return ( *pFuncAddr == NULL ? 1 : 0 ); +} + +/*************************************************************************** + * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID + * per call. It is called from root_dse_info (root_dse.c). + * The function is a modified version of get_supported_extop (file extended.c). + ***************************************************************************/ +struct berval * +slapi_int_get_supported_extop( int index ) +{ + ExtendedOp *ext; + + for ( ext = pGExtendedOps ; ext != NULL && --index >= 0; + ext = ext->ext_next) { + ; /* empty */ + } + + if ( ext == NULL ) { + return NULL; + } + + return &ext->ext_oid ; +} + +/********************************************************************* + * Function Name: slapi_int_load_plugin + * + * Description: This routine loads the specified DLL, gets and executes the init function + * if requested. + * + * Input: + * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to + * the DLL init function. + * path - path name of the DLL to be load. + * initfunc - either the DLL initialization function or an OID of the + * loaded extended operation. + * doInit - if it is TRUE, execute the init function, otherwise, save the + * function address but not execute it. + * + * Output: pInitFunc - the function address of the loaded function. This param + * should be not be null if doInit is FALSE. + * pLdHandle - handle returned by lt_dlopen() + * + * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR + * + * Messages: None + *********************************************************************/ + +static int +slapi_int_load_plugin( + Slapi_PBlock *pPlugin, + const char *path, + const char *initfunc, + int doInit, + SLAPI_FUNC *pInitFunc, + lt_dlhandle *pLdHandle ) +{ + int rc = LDAP_SUCCESS; + SLAPI_FUNC fpInitFunc = NULL; + + assert( pLdHandle != NULL ); + + if ( lt_dlinit() ) { + return LDAP_LOCAL_ERROR; + } + + /* load in the module */ + *pLdHandle = lt_dlopen( path ); + if ( *pLdHandle == NULL ) { + fprintf( stderr, "failed to load plugin %s: %s\n", + path, lt_dlerror() ); + return LDAP_LOCAL_ERROR; + } + + fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc ); + if ( fpInitFunc == NULL ) { + fprintf( stderr, "failed to find symbol %s in plugin %s: %s\n", + initfunc, path, lt_dlerror() ); + lt_dlclose( *pLdHandle ); + return LDAP_LOCAL_ERROR; + } + + if ( doInit ) { + rc = ( *fpInitFunc )( pPlugin ); + if ( rc != LDAP_SUCCESS ) { + lt_dlclose( *pLdHandle ); + } + + } else { + *pInitFunc = fpInitFunc; + } + + return rc; +} + +/* + * Special support for computed attribute plugins + */ +int +slapi_int_call_plugins( + Backend *be, + int funcType, + Slapi_PBlock *pPB ) +{ + + int rc = 0; + SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL; + + if ( pPB == NULL ) { + return 1; + } + + rc = slapi_int_get_plugins( be, funcType, &tmpPlugin ); + if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) { + /* Nothing to do, front-end should ignore. */ + return rc; + } + + for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) { + rc = (*pGetPlugin)(pPB); + + /* + * Only non-postoperation plugins abort processing on + * failure (confirmed with SLAPI specification). + */ + if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) { + /* + * Plugins generally return negative error codes + * to indicate failure, although in the case of + * bind plugins they may return SLAPI_BIND_xxx + */ + break; + } + } + + slapi_ch_free( (void **)&tmpPlugin ); + + return rc; +} + +int +slapi_int_read_config( + Backend *be, + const char *fname, + int lineno, + int argc, + char **argv ) +{ + int iType = -1; + int numPluginArgc = 0; + + if ( argc < 4 ) { + fprintf( stderr, + "%s: line %d: missing arguments " + "in \"plugin <plugin_type> <lib_path> " + "<init_function> [<arguments>]\" line\n", + fname, lineno ); + return 1; + } + + /* automatically instantiate overlay if necessary */ + if ( !slapi_over_is_inst( be ) ) { + ConfigReply cr = { 0 }; + if ( slapi_over_config( be, &cr ) != 0 ) { + fprintf( stderr, "Failed to instantiate SLAPI overlay: " + "err=%d msg=\"%s\"\n", cr.err, cr.msg ); + return -1; + } + } + + if ( strcasecmp( argv[1], "preoperation" ) == 0 ) { + iType = SLAPI_PLUGIN_PREOPERATION; + } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) { + iType = SLAPI_PLUGIN_POSTOPERATION; + } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) { + iType = SLAPI_PLUGIN_EXTENDEDOP; + } else if ( strcasecmp( argv[1], "object" ) == 0 ) { + iType = SLAPI_PLUGIN_OBJECT; + } else { + fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n", + fname, lineno, argv[1] ); + return 1; + } + + numPluginArgc = argc - 4; + + if ( iType == SLAPI_PLUGIN_PREOPERATION || + iType == SLAPI_PLUGIN_EXTENDEDOP || + iType == SLAPI_PLUGIN_POSTOPERATION || + iType == SLAPI_PLUGIN_OBJECT ) { + int rc; + Slapi_PBlock *pPlugin; + + pPlugin = plugin_pblock_new( iType, numPluginArgc, argv ); + if (pPlugin == NULL) { + return 1; + } + + if (iType == SLAPI_PLUGIN_EXTENDEDOP) { + rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin); + if ( rc != LDAP_SUCCESS ) { + slapi_pblock_destroy( pPlugin ); + return 1; + } + } + + rc = slapi_int_register_plugin( be, pPlugin ); + if ( rc != LDAP_SUCCESS ) { + if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) { + slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin ); + } + slapi_pblock_destroy( pPlugin ); + return 1; + } + } + + return 0; +} + +void +slapi_int_plugin_unparse( + Backend *be, + BerVarray *out +) +{ + Slapi_PBlock *pp; + int i, j; + char **argv, ibuf[32], *ptr; + struct berval idx, bv; + + *out = NULL; + idx.bv_val = ibuf; + i = 0; + + for ( pp = SLAPI_BACKEND_PBLOCK( be ); + pp != NULL; + slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) ) + { + slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv ); + if ( argv == NULL ) /* could be dynamic plugin */ + continue; + idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i ); + if ( idx.bv_len >= sizeof( ibuf ) ) { + /* FIXME: just truncating by now */ + idx.bv_len = sizeof( ibuf ) - 1; + } + bv.bv_len = idx.bv_len; + for (j=1; argv[j]; j++) { + bv.bv_len += strlen(argv[j]); + if ( j ) bv.bv_len++; + } + bv.bv_val = ch_malloc( bv.bv_len + 1 ); + ptr = lutil_strcopy( bv.bv_val, ibuf ); + for (j=1; argv[j]; j++) { + if ( j ) *ptr++ = ' '; + ptr = lutil_strcopy( ptr, argv[j] ); + } + ber_bvarray_add( out, &bv ); + } +} + diff --git a/servers/slapd/slapi/printmsg.c b/servers/slapd/slapi/printmsg.c new file mode 100644 index 0000000..498e78d --- /dev/null +++ b/servers/slapd/slapi/printmsg.c @@ -0,0 +1,100 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2002-2021 The OpenLDAP Foundation. + * Portions Copyright 1997,2002-2003 IBM Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by IBM Corporation for use in + * IBM products and subsequently ported to OpenLDAP Software by + * Steve Omrani. + */ + +#include <portable.h> +#include <stdio.h> +#include <ac/string.h> +#include <ac/stdarg.h> +#include <ac/unistd.h> +#include <fcntl.h> +#include <ac/errno.h> + +#include <ldap.h> +#include <ldap_config.h> +#include <slap.h> +#include <slapi.h> + +#include <ldap_pvt_thread.h> + +/* Single threads access to routine */ +ldap_pvt_thread_mutex_t slapi_printmessage_mutex; +char *slapi_log_file = NULL; +int slapi_log_level = SLAPI_LOG_PLUGIN; + +int +slapi_int_log_error( + int level, + char *subsystem, + char *fmt, + va_list arglist ) +{ + int rc = 0; + FILE *fp = NULL; + + char timeStr[100]; + struct tm *ltm; + time_t currentTime; + + assert( subsystem != NULL ); + assert( fmt != NULL ); + + ldap_pvt_thread_mutex_lock( &slapi_printmessage_mutex ) ; + + /* for now, we log all severities */ + if ( level <= slapi_log_level ) { + fp = fopen( slapi_log_file, "a" ); + if ( fp == NULL) { + rc = -1; + goto done; + } + + /* + * FIXME: could block + */ + while ( lockf( fileno( fp ), F_LOCK, 0 ) != 0 ) { + /* DO NOTHING */ ; + } + + time( ¤tTime ); + ltm = localtime( ¤tTime ); + strftime( timeStr, sizeof(timeStr), "%x %X", ltm ); + fputs( timeStr, fp ); + + fprintf( fp, " %s: ", subsystem ); + vfprintf( fp, fmt, arglist ); + if ( fmt[ strlen( fmt ) - 1 ] != '\n' ) { + fputs( "\n", fp ); + } + fflush( fp ); + + lockf( fileno( fp ), F_ULOCK, 0 ); + + fclose( fp ); + + } else { + rc = -1; + } + +done: + ldap_pvt_thread_mutex_unlock( &slapi_printmessage_mutex ); + + return rc; +} diff --git a/servers/slapd/slapi/proto-slapi.h b/servers/slapd/slapi/proto-slapi.h new file mode 100644 index 0000000..0f11145 --- /dev/null +++ b/servers/slapd/slapi/proto-slapi.h @@ -0,0 +1,91 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2002-2021 The OpenLDAP Foundation. + * Portions Copyright 1997,2002-2003 IBM Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by IBM Corporation for use in + * IBM products and subsequently ported to OpenLDAP Software by + * Steve Omrani. Additional significant contributors include: + * Luke Howard + */ + +#ifndef _PROTO_SLAPI_H +#define _PROTO_SLAPI_H + +LDAP_BEGIN_DECL + +/* slapi_utils.c */ +LDAP_SLAPI_F (LDAPMod **) slapi_int_modifications2ldapmods LDAP_P(( Modifications * )); +LDAP_SLAPI_F (Modifications *) slapi_int_ldapmods2modifications LDAP_P(( Operation *op, LDAPMod ** )); +LDAP_SLAPI_F (int) slapi_int_count_controls LDAP_P(( LDAPControl **ctrls )); +LDAP_SLAPI_F (char **) slapi_get_supported_extended_ops LDAP_P((void)); +LDAP_SLAPI_F (int) slapi_int_access_allowed LDAP_P((Operation *op, Entry *entry, AttributeDescription *desc, struct berval *val, slap_access_t access, AccessControlState *state )); + +/* slapi_ops.c */ +LDAP_SLAPI_F (int) slapi_int_response LDAP_P(( Slapi_Operation *op, SlapReply *rs )); +LDAP_SLAPI_F (void) slapi_int_connection_init_pb LDAP_P(( Slapi_PBlock *pb, ber_tag_t OpType )); +LDAP_SLAPI_F (void) slapi_int_connection_done_pb LDAP_P(( Slapi_PBlock *pb )); + +/* slapi_pblock.c */ +LDAP_SLAPI_F (int) slapi_pblock_delete_param LDAP_P(( Slapi_PBlock *p, int param )); +LDAP_SLAPI_F (void) slapi_pblock_clear LDAP_P(( Slapi_PBlock *pb )); + +LDAP_SLAPI_F (int) slapi_int_pblock_get_first LDAP_P(( Backend *be, Slapi_PBlock **pb )); +LDAP_SLAPI_F (int) slapi_int_pblock_get_next LDAP_P(( Slapi_PBlock **pb )); + +#define PBLOCK_ASSERT_CONN( _pb ) do { \ + assert( (_pb) != NULL ); \ + assert( (_pb)->pb_conn != NULL ); \ + } while (0) + +#define PBLOCK_ASSERT_OP( _pb, _tag ) do { \ + PBLOCK_ASSERT_CONN( _pb ); \ + assert( (_pb)->pb_op != NULL ); \ + assert( (_pb)->pb_rs != NULL ); \ + if ( _tag != 0 ) \ + assert( (_pb)->pb_op->o_tag == (_tag)); \ + } while (0) + +#define PBLOCK_ASSERT_INTOP( _pb, _tag ) do { \ + PBLOCK_ASSERT_OP( _pb, _tag ); \ + assert( (_pb)->pb_intop ); \ + assert( (_pb)->pb_op == (Operation *)pb->pb_conn->c_pending_ops.stqh_first ); \ + } while (0) + +/* plugin.c */ +LDAP_SLAPI_F (int) slapi_int_register_plugin LDAP_P((Backend *be, Slapi_PBlock *pPB)); +LDAP_SLAPI_F (int) slapi_int_call_plugins LDAP_P((Backend *be, int funcType, Slapi_PBlock * pPB)); +LDAP_SLAPI_F (int) slapi_int_get_plugins LDAP_P((Backend *be, int functype, SLAPI_FUNC **ppFuncPtrs)); +LDAP_SLAPI_F (int) slapi_int_register_extop LDAP_P((Backend *pBE, ExtendedOp **opList, Slapi_PBlock *pPB)); +LDAP_SLAPI_F (int) slapi_int_get_extop_plugin LDAP_P((struct berval *reqoid, SLAPI_FUNC *pFuncAddr )); +LDAP_SLAPI_F (struct berval *) slapi_int_get_supported_extop LDAP_P(( int )); +LDAP_SLAPI_F (int) slapi_int_read_config LDAP_P((Backend *be, const char *fname, int lineno, + int argc, char **argv )); +LDAP_SLAPI_F (void) slapi_int_plugin_unparse LDAP_P((Backend *be, BerVarray *out )); +LDAP_SLAPI_F (int) slapi_int_initialize LDAP_P((void)); + +/* slapi_ext.c */ +LDAP_SLAPI_F (int) slapi_int_init_object_extensions LDAP_P((void)); +LDAP_SLAPI_F (int) slapi_int_free_object_extensions LDAP_P((int objecttype, void *object)); +LDAP_SLAPI_F (int) slapi_int_create_object_extensions LDAP_P((int objecttype, void *object)); +LDAP_SLAPI_F (int) slapi_int_clear_object_extensions LDAP_P((int objecttype, void *object)); + +/* slapi_overlay.c */ +LDAP_SLAPI_F (int) slapi_over_is_inst LDAP_P((BackendDB *)); +LDAP_SLAPI_F (int) slapi_over_config LDAP_P((BackendDB *, ConfigReply *)); + +LDAP_END_DECL + +#endif /* _PROTO_SLAPI_H */ + diff --git a/servers/slapd/slapi/slapi.h b/servers/slapd/slapi/slapi.h new file mode 100644 index 0000000..f772743 --- /dev/null +++ b/servers/slapd/slapi/slapi.h @@ -0,0 +1,204 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2002-2021 The OpenLDAP Foundation. + * Portions Copyright 1997,2002-2003 IBM Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by IBM Corporation for use in + * IBM products and subsequently ported to OpenLDAP Software by + * Steve Omrani. Additional significant contributors include: + * Luke Howard + */ + +#ifdef LDAP_SLAPI /* SLAPI is OPTIONAL */ + +#ifndef _SLAPI_H +#define _SLAPI_H + +LDAP_BEGIN_DECL + +/* + * Quick 'n' dirty to make struct slapi_* in slapi-plugin.h opaque + */ +#define slapi_entry Entry +#define slapi_attr Attribute +#define slapi_value berval +#define slapi_valueset berval * +#define slapi_filter Filter + +LDAP_END_DECL + +#include <slapi-plugin.h> + +LDAP_BEGIN_DECL + +#define SLAPI_OVERLAY_NAME "slapi" + +#define SLAPI_OPERATION_PBLOCK(_op) ((_op)->o_callback->sc_private) +#define SLAPI_BACKEND_PBLOCK(_be) ((_be)->be_pb) + +#define SLAPI_OPERATION_EXTENSIONS(_op) ((_op)->o_hdr->oh_extensions) +#define SLAPI_CONNECTION_EXTENSIONS(_conn) ((_conn)->c_extensions) + +#define SLAPI_CONTROL_MANAGEDSAIT_OID LDAP_CONTROL_MANAGEDSAIT +#define SLAPI_CONTROL_SORTEDSEARCH_OID LDAP_CONTROL_SORTREQUEST +#define SLAPI_CONTROL_PAGED_RESULTS_OID LDAP_CONTROL_PAGEDRESULTS + +typedef int (*SLAPI_FUNC)( Slapi_PBlock *pb ); + +typedef struct _slapi_control { + int s_ctrl_num; + char **s_ctrl_oids; + unsigned long *s_ctrl_ops; +} Slapi_Control; + +typedef struct _ExtendedOp { + struct berval ext_oid; + SLAPI_FUNC ext_func; + Backend *ext_be; + struct _ExtendedOp *ext_next; +} ExtendedOp; + +/* Computed attribute support */ +struct _computed_attr_context { + Slapi_PBlock *cac_pb; + Operation *cac_op; + void *cac_private; +}; + +/* for slapi_attr_type_cmp() */ +#define SLAPI_TYPE_CMP_EXACT 0 +#define SLAPI_TYPE_CMP_BASE 1 +#define SLAPI_TYPE_CMP_SUBTYPE 2 + +typedef enum slapi_extension_e { + SLAPI_X_EXT_CONNECTION = 0, + SLAPI_X_EXT_OPERATION = 1, + SLAPI_X_EXT_MAX = 2 +} slapi_extension_t; + +struct slapi_dn { + unsigned char flag; + struct berval dn; + struct berval ndn; +}; + +struct slapi_rdn { + unsigned char flag; + struct berval bv; + LDAPRDN rdn; +}; + +/* + * Was: slapi_pblock.h + */ + +#ifndef NO_PBLOCK_CLASS /* where's this test from? */ + +typedef enum slapi_pblock_class_e { + PBLOCK_CLASS_INVALID = 0, + PBLOCK_CLASS_INTEGER, + PBLOCK_CLASS_LONG_INTEGER, + PBLOCK_CLASS_POINTER, + PBLOCK_CLASS_FUNCTION_POINTER +} slapi_pblock_class_t; + +#define PBLOCK_SUCCESS (0) +#define PBLOCK_ERROR (-1) +#define PBLOCK_MAX_PARAMS 100 + +union slapi_pblock_value { + int pv_integer; + long pv_long_integer; + void *pv_pointer; + int (*pv_function_pointer)(); +}; + +struct slapi_pblock { + ldap_pvt_thread_mutex_t pb_mutex; + int pb_nParams; + int pb_params[PBLOCK_MAX_PARAMS]; + union slapi_pblock_value pb_values[PBLOCK_MAX_PARAMS]; + /* native types */ + Connection *pb_conn; + Operation *pb_op; + SlapReply *pb_rs; + int pb_intop; + char pb_textbuf[ SLAP_TEXT_BUFLEN ]; +}; + +#endif /* !NO_PBLOCK_CLASS */ + +/* + * Was: plugin.h + */ + +#define SLAPI_PLUGIN_IS_POST_FN(x) ((x) >= SLAPI_PLUGIN_POST_BIND_FN && (x) <= SLAPI_PLUGIN_BE_POST_DELETE_FN) + +#define SLAPI_IBM_PBLOCK -3 + +#define SLAPI_ENTRY_PRE_OP 52 +#define SLAPI_ENTRY_POST_OP 53 + +/* This is the spelling in the SunOne 5.2 docs */ +#define SLAPI_RES_CONTROLS SLAPI_RESCONTROLS + +#define SLAPI_ABANDON_MSGID 120 + +#define SLAPI_OPERATION_PARAMETERS 138 + +#define SLAPI_SEQ_TYPE 150 +#define SLAPI_SEQ_ATTRNAME 151 +#define SLAPI_SEQ_VAL 152 + +#define SLAPI_MR_FILTER_ENTRY 170 +#define SLAPI_MR_FILTER_TYPE 171 +#define SLAPI_MR_FILTER_VALUE 172 +#define SLAPI_MR_FILTER_OID 173 +#define SLAPI_MR_FILTER_DNATTRS 174 + +#define SLAPI_LDIF2DB_FILE 180 +#define SLAPI_LDIF2DB_REMOVEDUPVALS 185 + +#define SLAPI_DB2LDIF_PRINTKEY 183 + +#define SLAPI_CHANGENUMBER 197 +#define SLAPI_LOG_OPERATION 198 + +#define SLAPI_DBSIZE 199 + +#define SLAPI_PLUGIN_DB_TEST_FN 227 +#define SLAPI_PLUGIN_DB_NO_ACL 250 + +/* OpenLDAP private parametrs */ +#define SLAPI_PLUGIN_COMPUTE_EVALUATOR_FN 1200 +#define SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN 1201 + +#define SLAPI_X_CONFIG_ARGV 1400 +#define SLAPI_X_INTOP_FLAGS 1401 +#define SLAPI_X_INTOP_RESULT_CALLBACK 1402 +#define SLAPI_X_INTOP_SEARCH_ENTRY_CALLBACK 1403 +#define SLAPI_X_INTOP_REFERRAL_ENTRY_CALLBACK 1404 +#define SLAPI_X_INTOP_CALLBACK_DATA 1405 +#define SLAPI_X_OLD_RESCONTROLS 1406 + +LDAP_SLAPI_V (ldap_pvt_thread_mutex_t) slapi_hn_mutex; +LDAP_SLAPI_V (ldap_pvt_thread_mutex_t) slapi_time_mutex; +LDAP_SLAPI_V (ldap_pvt_thread_mutex_t) slapi_printmessage_mutex; +LDAP_SLAPI_V (char *) slapi_log_file; +LDAP_SLAPI_V (int) slapi_log_level; + +#include "proto-slapi.h" + +#endif /* _SLAPI_H */ +#endif /* LDAP_SLAPI */ diff --git a/servers/slapd/slapi/slapi_dn.c b/servers/slapd/slapi/slapi_dn.c new file mode 100644 index 0000000..238a48e --- /dev/null +++ b/servers/slapd/slapi/slapi_dn.c @@ -0,0 +1,669 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2005-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Luke Howard for inclusion + * in OpenLDAP Software. + */ + +#include "portable.h" + +#include <ac/string.h> +#include <ac/stdarg.h> +#include <ac/ctype.h> +#include <ac/unistd.h> +#include <ldap_pvt.h> + +#include <slap.h> +#include <slapi.h> + +#ifdef LDAP_SLAPI +#define FLAG_DN 0x1 +#define FLAG_NDN 0x2 + +void slapi_sdn_init( Slapi_DN *sdn ) +{ + sdn->flag = 0; + BER_BVZERO( &sdn->dn ); + BER_BVZERO( &sdn->ndn ); +} + +Slapi_DN *slapi_sdn_new( void ) +{ + Slapi_DN *sdn; + + sdn = (Slapi_DN *)slapi_ch_malloc( sizeof(*sdn )); + slapi_sdn_init( sdn ); + + return sdn; +} + +void slapi_sdn_done( Slapi_DN *sdn ) +{ + if ( sdn == NULL ) + return; + + if ( sdn->flag & FLAG_DN ) { + slapi_ch_free_string( &sdn->dn.bv_val ); + } + if ( sdn->flag & FLAG_NDN ) { + slapi_ch_free_string( &sdn->ndn.bv_val ); + } + + slapi_sdn_init( sdn ); +} + +void slapi_sdn_free( Slapi_DN **sdn ) +{ + slapi_sdn_done( *sdn ); + slapi_ch_free( (void **)sdn ); +} + +const char *slapi_sdn_get_dn( const Slapi_DN *sdn ) +{ + if ( !BER_BVISNULL( &sdn->dn ) ) + return sdn->dn.bv_val; + else + return sdn->ndn.bv_val; +} + +const char *slapi_sdn_get_ndn( const Slapi_DN *sdn ) +{ + if ( BER_BVISNULL( &sdn->ndn ) ) { + dnNormalize( 0, NULL, NULL, + (struct berval *)&sdn->dn, (struct berval *)&sdn->ndn, NULL ); + ((Slapi_DN *)sdn)->flag |= FLAG_NDN; + } + + return sdn->ndn.bv_val; +} + +Slapi_DN *slapi_sdn_new_dn_byval( const char *dn ) +{ + Slapi_DN *sdn; + + sdn = slapi_sdn_new(); + return slapi_sdn_set_dn_byval( sdn, dn ); +} + +Slapi_DN *slapi_sdn_new_ndn_byval( const char *ndn ) +{ + Slapi_DN *sdn; + + sdn = slapi_sdn_new(); + return slapi_sdn_set_ndn_byval( sdn, ndn ); +} + +Slapi_DN *slapi_sdn_new_dn_byref( const char *dn ) +{ + Slapi_DN *sdn; + + sdn = slapi_sdn_new(); + return slapi_sdn_set_dn_byref( sdn, dn ); +} + +Slapi_DN *slapi_sdn_new_ndn_byref( const char *ndn ) +{ + Slapi_DN *sdn; + + sdn = slapi_sdn_new(); + return slapi_sdn_set_ndn_byref( sdn, ndn ); +} + +Slapi_DN *slapi_sdn_new_dn_passin( const char *dn ) +{ + Slapi_DN *sdn; + + sdn = slapi_sdn_new(); + return slapi_sdn_set_dn_passin( sdn, dn ); +} + +Slapi_DN *slapi_sdn_set_dn_byval( Slapi_DN *sdn, const char *dn ) +{ + if ( sdn == NULL ) { + return NULL; + } + + slapi_sdn_done( sdn ); + if ( dn != NULL ) { + sdn->dn.bv_val = slapi_ch_strdup( dn ); + sdn->dn.bv_len = strlen( dn ); + } + sdn->flag |= FLAG_DN; + + return sdn; +} + +Slapi_DN *slapi_sdn_set_dn_byref( Slapi_DN *sdn, const char *dn ) +{ + if ( sdn == NULL ) + return NULL; + + slapi_sdn_done( sdn ); + if ( dn != NULL ) { + sdn->dn.bv_val = (char *)dn; + sdn->dn.bv_len = strlen( dn ); + } + + return sdn; +} + +Slapi_DN *slapi_sdn_set_dn_passin( Slapi_DN *sdn, const char *dn ) +{ + if ( sdn == NULL ) + return NULL; + + slapi_sdn_set_dn_byref( sdn, dn ); + sdn->flag |= FLAG_DN; + + return sdn; +} + +Slapi_DN *slapi_sdn_set_ndn_byval( Slapi_DN *sdn, const char *ndn ) +{ + if ( sdn == NULL ) { + return NULL; + } + + slapi_sdn_done( sdn ); + if ( ndn != NULL ) { + sdn->ndn.bv_val = slapi_ch_strdup( ndn ); + sdn->ndn.bv_len = strlen( ndn ); + } + sdn->flag |= FLAG_NDN; + + return sdn; +} + +Slapi_DN *slapi_sdn_set_ndn_byref( Slapi_DN *sdn, const char *ndn ) +{ + if ( sdn == NULL ) + return NULL; + + slapi_sdn_done( sdn ); + if ( ndn != NULL ) { + sdn->ndn.bv_val = (char *)ndn; + sdn->ndn.bv_len = strlen( ndn ); + } + + return sdn; +} + +Slapi_DN *slapi_sdn_set_ndn_passin( Slapi_DN *sdn, const char *ndn ) +{ + if ( sdn == NULL ) + return NULL; + + slapi_sdn_set_ndn_byref( sdn, ndn ); + sdn->flag |= FLAG_NDN; + + return sdn; +} + +void slapi_sdn_get_parent( const Slapi_DN *sdn, Slapi_DN *sdn_parent ) +{ + struct berval parent_dn; + + if ( !(sdn->flag & FLAG_DN) ) { + dnParent( (struct berval *)&sdn->ndn, &parent_dn ); + slapi_sdn_set_ndn_byval( sdn_parent, parent_dn.bv_val ); + } else { + dnParent( (struct berval *)&sdn->dn, &parent_dn ); + slapi_sdn_set_dn_byval( sdn_parent, parent_dn.bv_val ); + } +} + +void slapi_sdn_get_backend_parent( const Slapi_DN *sdn, + Slapi_DN *sdn_parent, + const Slapi_Backend *backend ) +{ + slapi_sdn_get_ndn( sdn ); + + if ( backend == NULL || + be_issuffix( (Slapi_Backend *)backend, (struct berval *)&sdn->ndn ) == 0 ) { + slapi_sdn_get_parent( sdn, sdn_parent ); + } + +} + +Slapi_DN * slapi_sdn_dup( const Slapi_DN *sdn ) +{ + Slapi_DN *new_sdn; + + new_sdn = slapi_sdn_new(); + slapi_sdn_copy( sdn, new_sdn ); + + return new_sdn; +} + +void slapi_sdn_copy( const Slapi_DN *from, Slapi_DN *to ) +{ + slapi_sdn_set_dn_byval( to, from->dn.bv_val ); +} + +int slapi_sdn_compare( const Slapi_DN *sdn1, const Slapi_DN *sdn2 ) +{ + int match = -1; + + slapi_sdn_get_ndn( sdn1 ); + slapi_sdn_get_ndn( sdn2 ); + + dnMatch( &match, 0, slap_schema.si_syn_distinguishedName, NULL, + (struct berval *)&sdn1->ndn, (void *)&sdn2->ndn ); + + return match; +} + +int slapi_sdn_isempty( const Slapi_DN *sdn) +{ + return ( BER_BVISEMPTY( &sdn->dn ) && BER_BVISEMPTY( &sdn->ndn ) ); +} + +int slapi_sdn_issuffix( const Slapi_DN *sdn, const Slapi_DN *suffix_sdn ) +{ + slapi_sdn_get_ndn( sdn ); + slapi_sdn_get_ndn( suffix_sdn ); + + return dnIsSuffix( &sdn->ndn, &suffix_sdn->ndn ); +} + +int slapi_sdn_isparent( const Slapi_DN *parent, const Slapi_DN *child ) +{ + Slapi_DN child_parent; + + slapi_sdn_get_ndn( child ); + + slapi_sdn_init( &child_parent ); + dnParent( (struct berval *)&child->ndn, &child_parent.ndn ); + + return ( slapi_sdn_compare( parent, &child_parent ) == 0 ); +} + +int slapi_sdn_isgrandparent( const Slapi_DN *parent, const Slapi_DN *child ) +{ + Slapi_DN child_grandparent; + + slapi_sdn_get_ndn( child ); + + slapi_sdn_init( &child_grandparent ); + dnParent( (struct berval *)&child->ndn, &child_grandparent.ndn ); + if ( child_grandparent.ndn.bv_len == 0 ) { + return 0; + } + + dnParent( &child_grandparent.ndn, &child_grandparent.ndn ); + + return ( slapi_sdn_compare( parent, &child_grandparent ) == 0 ); +} + +int slapi_sdn_get_ndn_len( const Slapi_DN *sdn ) +{ + slapi_sdn_get_ndn( sdn ); + + return sdn->ndn.bv_len; +} + +int slapi_sdn_scope_test( const Slapi_DN *dn, const Slapi_DN *base, int scope ) +{ + int rc; + + switch ( scope ) { + case LDAP_SCOPE_BASE: + rc = ( slapi_sdn_compare( dn, base ) == 0 ); + break; + case LDAP_SCOPE_ONELEVEL: + rc = slapi_sdn_isparent( base, dn ); + break; + case LDAP_SCOPE_SUBTREE: + rc = slapi_sdn_issuffix( dn, base ); + break; + default: + rc = 0; + break; + } + + return rc; +} + +void slapi_rdn_init( Slapi_RDN *rdn ) +{ + rdn->flag = 0; + BER_BVZERO( &rdn->bv ); + rdn->rdn = NULL; +} + +Slapi_RDN *slapi_rdn_new( void ) +{ + Slapi_RDN *rdn; + + rdn = (Slapi_RDN *)slapi_ch_malloc( sizeof(*rdn )); + slapi_rdn_init( rdn ); + + return rdn; +} + +Slapi_RDN *slapi_rdn_new_dn( const char *dn ) +{ + Slapi_RDN *rdn; + + rdn = slapi_rdn_new(); + slapi_rdn_init_dn( rdn, dn ); + return rdn; +} + +Slapi_RDN *slapi_rdn_new_sdn( const Slapi_DN *sdn ) +{ + return slapi_rdn_new_dn( slapi_sdn_get_dn( sdn ) ); +} + +Slapi_RDN *slapi_rdn_new_rdn( const Slapi_RDN *fromrdn ) +{ + return slapi_rdn_new_dn( fromrdn->bv.bv_val ); +} + +void slapi_rdn_init_dn( Slapi_RDN *rdn, const char *dn ) +{ + slapi_rdn_init( rdn ); + slapi_rdn_set_dn( rdn, dn ); +} + +void slapi_rdn_init_sdn( Slapi_RDN *rdn, const Slapi_DN *sdn ) +{ + slapi_rdn_init( rdn ); + slapi_rdn_set_sdn( rdn, sdn ); +} + +void slapi_rdn_init_rdn( Slapi_RDN *rdn, const Slapi_RDN *fromrdn ) +{ + slapi_rdn_init( rdn ); + slapi_rdn_set_rdn( rdn, fromrdn ); +} + +void slapi_rdn_set_dn( Slapi_RDN *rdn, const char *dn ) +{ + struct berval bv; + + slapi_rdn_done( rdn ); + + BER_BVZERO( &bv ); + + if ( dn != NULL ) { + bv.bv_val = (char *)dn; + bv.bv_len = strlen( dn ); + } + + dnExtractRdn( &bv, &rdn->bv, NULL ); + rdn->flag |= FLAG_DN; +} + +void slapi_rdn_set_sdn( Slapi_RDN *rdn, const Slapi_DN *sdn ) +{ + slapi_rdn_set_dn( rdn, slapi_sdn_get_dn( sdn ) ); +} + +void slapi_rdn_set_rdn( Slapi_RDN *rdn, const Slapi_RDN *fromrdn ) +{ + slapi_rdn_set_dn( rdn, fromrdn->bv.bv_val ); +} + +void slapi_rdn_free( Slapi_RDN **rdn ) +{ + slapi_rdn_done( *rdn ); + slapi_ch_free( (void **)rdn ); +} + +void slapi_rdn_done( Slapi_RDN *rdn ) +{ + if ( rdn->rdn != NULL ) { + ldap_rdnfree( rdn->rdn ); + rdn->rdn = NULL; + } + slapi_ch_free_string( &rdn->bv.bv_val ); + slapi_rdn_init( rdn ); +} + +const char *slapi_rdn_get_rdn( const Slapi_RDN *rdn ) +{ + return rdn->bv.bv_val; +} + +static int slapi_int_rdn_explode( Slapi_RDN *rdn ) +{ + char *next; + + if ( rdn->rdn != NULL ) { + return LDAP_SUCCESS; + } + + return ldap_bv2rdn( &rdn->bv, &rdn->rdn, &next, LDAP_DN_FORMAT_LDAP ); +} + +static int slapi_int_rdn_implode( Slapi_RDN *rdn ) +{ + struct berval bv; + int rc; + + if ( rdn->rdn == NULL ) { + return LDAP_SUCCESS; + } + + rc = ldap_rdn2bv( rdn->rdn, &bv, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + slapi_ch_free_string( &rdn->bv.bv_val ); + rdn->bv = bv; + + return 0; +} + +int slapi_rdn_get_num_components( Slapi_RDN *rdn ) +{ + int i; + + if ( slapi_int_rdn_explode( rdn ) != LDAP_SUCCESS ) + return 0; + + for ( i = 0; rdn->rdn[i] != NULL; i++ ) + ; + + return i; +} + +int slapi_rdn_get_first( Slapi_RDN *rdn, char **type, char **value ) +{ + return slapi_rdn_get_next( rdn, 0, type, value ); +} + +int slapi_rdn_get_next( Slapi_RDN *rdn, int index, char **type, char **value ) +{ + slapi_int_rdn_explode( rdn ); + + if ( rdn->rdn == NULL || rdn->rdn[index] == NULL ) + return -1; + + *type = rdn->rdn[index]->la_attr.bv_val; + *value = rdn->rdn[index]->la_value.bv_val; + + return index + 1; +} + +int slapi_rdn_get_index( Slapi_RDN *rdn, const char *type, const char *value, size_t length ) +{ + int i, match; + struct berval bv; + AttributeDescription *ad = NULL; + const char *text; + + slapi_int_rdn_explode( rdn ); + + if ( slap_str2ad( type, &ad, &text ) != LDAP_SUCCESS ) { + return -1; + } + + bv.bv_val = (char *)value; + bv.bv_len = length; + + for ( i = 0; rdn->rdn[i] != NULL; i++ ) { + if ( !slapi_attr_types_equivalent( ad->ad_cname.bv_val, type )) + continue; + + if ( value_match( &match, ad, ad->ad_type->sat_equality, 0, + &rdn->rdn[i]->la_value, (void *)&bv, &text ) != LDAP_SUCCESS ) + match = -1; + + if ( match == 0 ) + return i; + } + + return -1; +} + +int slapi_rdn_get_index_attr( Slapi_RDN *rdn, const char *type, char **value ) +{ + int i; + + for ( i = 0; rdn->rdn[i] != NULL; i++ ) { + if ( slapi_attr_types_equivalent( rdn->rdn[i]->la_attr.bv_val, type ) ) { + *value = rdn->rdn[i]->la_value.bv_val; + return i; + } + } + + return -1; +} + +int slapi_rdn_contains( Slapi_RDN *rdn, const char *type, const char *value, size_t length ) +{ + return ( slapi_rdn_get_index( rdn, type, value, length ) != -1 ); +} + +int slapi_rdn_contains_attr( Slapi_RDN *rdn, const char *type, char **value ) +{ + return ( slapi_rdn_get_index_attr( rdn, type, value ) != -1 ); +} + +int slapi_rdn_compare( Slapi_RDN *rdn1, Slapi_RDN *rdn2 ) +{ + struct berval nrdn1 = BER_BVNULL; + struct berval nrdn2 = BER_BVNULL; + int match; + + rdnNormalize( 0, NULL, NULL, (struct berval *)&rdn1->bv, &nrdn1, NULL ); + rdnNormalize( 0, NULL, NULL, (struct berval *)&rdn2->bv, &nrdn2, NULL ); + + if ( rdnMatch( &match, 0, NULL, NULL, &nrdn1, (void *)&nrdn2 ) != LDAP_SUCCESS) { + match = -1; + } + + return match; +} + +int slapi_rdn_isempty( const Slapi_RDN *rdn ) +{ + return ( BER_BVISEMPTY( &rdn->bv ) ); +} + +int slapi_rdn_add( Slapi_RDN *rdn, const char *type, const char *value ) +{ + char *s; + size_t len; + + len = strlen(type) + 1 + strlen( value ); + if ( !BER_BVISEMPTY( &rdn->bv ) ) { + len += 1 + rdn->bv.bv_len; + } + + s = slapi_ch_malloc( len + 1 ); + + if ( BER_BVISEMPTY( &rdn->bv ) ) { + snprintf( s, len + 1, "%s=%s", type, value ); + } else { + snprintf( s, len + 1, "%s=%s+%s", type, value, rdn->bv.bv_val ); + } + + slapi_rdn_done( rdn ); + + rdn->bv.bv_len = len; + rdn->bv.bv_val = s; + + return 1; +} + +int slapi_rdn_remove_index( Slapi_RDN *rdn, int atindex ) +{ + int count, i; + + count = slapi_rdn_get_num_components( rdn ); + + if ( atindex < 0 || atindex >= count ) + return 0; + + if ( rdn->rdn == NULL ) + return 0; + + slapi_ch_free_string( &rdn->rdn[atindex]->la_attr.bv_val ); + slapi_ch_free_string( &rdn->rdn[atindex]->la_value.bv_val ); + + for ( i = atindex; i < count; i++ ) { + rdn->rdn[i] = rdn->rdn[i + 1]; + } + + if ( slapi_int_rdn_implode( rdn ) != LDAP_SUCCESS ) + return 0; + + return 1; +} + +int slapi_rdn_remove( Slapi_RDN *rdn, const char *type, const char *value, size_t length ) +{ + int index = slapi_rdn_get_index( rdn, type, value, length ); + + return slapi_rdn_remove_index( rdn, index ); +} + +int slapi_rdn_remove_attr( Slapi_RDN *rdn, const char *type ) +{ + char *value; + int index = slapi_rdn_get_index_attr( rdn, type, &value ); + + return slapi_rdn_remove_index( rdn, index ); +} + +Slapi_DN *slapi_sdn_add_rdn( Slapi_DN *sdn, const Slapi_RDN *rdn ) +{ + struct berval bv; + + build_new_dn( &bv, &sdn->dn, (struct berval *)&rdn->bv, NULL ); + + slapi_sdn_done( sdn ); + sdn->dn = bv; + + return sdn; +} + +Slapi_DN *slapi_sdn_set_parent( Slapi_DN *sdn, const Slapi_DN *parentdn ) +{ + Slapi_RDN rdn; + + slapi_rdn_init_sdn( &rdn, sdn ); + slapi_sdn_set_dn_byref( sdn, slapi_sdn_get_dn( parentdn ) ); + slapi_sdn_add_rdn( sdn, &rdn ); + slapi_rdn_done( &rdn ); + + return sdn; +} + +#endif /* LDAP_SLAPI */ diff --git a/servers/slapd/slapi/slapi_ext.c b/servers/slapd/slapi/slapi_ext.c new file mode 100644 index 0000000..5380a2c --- /dev/null +++ b/servers/slapd/slapi/slapi_ext.c @@ -0,0 +1,349 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2003-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* (C) Copyright PADL Software Pty Ltd. 2003 + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is preserved + * and that due credit is given to PADL Software Pty Ltd. This software + * is provided ``as is'' without express or implied warranty. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Luke Howard for inclusion + * in OpenLDAP Software. + */ + +#include "portable.h" + +#include <ac/string.h> +#include <ac/stdarg.h> +#include <ac/ctype.h> +#include <ac/unistd.h> + +#ifdef LDAP_SLAPI + +#include <slap.h> +#include <slapi.h> + +/* + * Object extensions + * + * We only support two types -- connection and operation extensions. + * Define more types in slapi.h + */ + +/* global state */ +struct slapi_registered_extension_set { + ldap_pvt_thread_mutex_t mutex; + struct slapi_registered_extension { + int active; + int count; + slapi_extension_constructor_fnptr *constructors; + slapi_extension_destructor_fnptr *destructors; + } extensions[SLAPI_X_EXT_MAX]; +} registered_extensions; + +/* per-object state */ +struct slapi_extension_block { + void **extensions; +}; + +static int get_extension_block(int objecttype, void *object, struct slapi_extension_block **eblock, void **parent) +{ + switch ((slapi_extension_t) objecttype) { + case SLAPI_X_EXT_CONNECTION: + *eblock = ((Connection *)object)->c_extensions; + *parent = NULL; + break; + case SLAPI_X_EXT_OPERATION: + *eblock = ((Operation *)object)->o_hdr->oh_extensions; + *parent = ((Operation *)object)->o_conn; + break; + default: + return -1; + break; + } + + if ( *eblock == NULL ) { + return -1; + } + + return 0; +} + +static int map_extension_type(const char *objectname, slapi_extension_t *type) +{ + if ( strcasecmp( objectname, SLAPI_EXT_CONNECTION ) == 0 ) { + *type = SLAPI_X_EXT_CONNECTION; + } else if ( strcasecmp( objectname, SLAPI_EXT_OPERATION ) == 0 ) { + *type = SLAPI_X_EXT_OPERATION; + } else { + return -1; + } + + return 0; +} + +static void new_extension(struct slapi_extension_block *eblock, + int objecttype, void *object, void *parent, + int extensionhandle ) +{ + slapi_extension_constructor_fnptr constructor; + + assert( objecttype < SLAPI_X_EXT_MAX ); + assert( extensionhandle < registered_extensions.extensions[objecttype].count ); + + assert( registered_extensions.extensions[objecttype].constructors != NULL ); + constructor = registered_extensions.extensions[objecttype].constructors[extensionhandle]; + + assert( eblock->extensions[extensionhandle] == NULL ); + + if ( constructor != NULL ) { + eblock->extensions[extensionhandle] = (*constructor)( object, parent ); + } else { + eblock->extensions[extensionhandle] = NULL; + } +} + +static void free_extension(struct slapi_extension_block *eblock, int objecttype, void *object, void *parent, int extensionhandle ) +{ + slapi_extension_destructor_fnptr destructor; + + assert( objecttype < SLAPI_X_EXT_MAX ); + assert( extensionhandle < registered_extensions.extensions[objecttype].count ); + + if ( eblock->extensions[extensionhandle] != NULL ) { + assert( registered_extensions.extensions[objecttype].destructors != NULL ); + destructor = registered_extensions.extensions[objecttype].destructors[extensionhandle]; + if ( destructor != NULL ) { + (*destructor)( eblock->extensions[extensionhandle], object, parent ); + } + eblock->extensions[extensionhandle] = NULL; + } +} + +void *slapi_get_object_extension(int objecttype, void *object, int extensionhandle) +{ + struct slapi_extension_block *eblock; + void *parent; + + if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) { + return NULL; + } + + if ( extensionhandle < registered_extensions.extensions[objecttype].count ) { + return eblock->extensions[extensionhandle]; + } + + return NULL; +} + +void slapi_set_object_extension(int objecttype, void *object, int extensionhandle, void *extension) +{ + struct slapi_extension_block *eblock; + void *parent; + + if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) { + return; + } + + if ( extensionhandle < registered_extensions.extensions[objecttype].count ) { + /* free the old one */ + free_extension( eblock, objecttype, object, parent, extensionhandle ); + + /* constructed by caller */ + eblock->extensions[extensionhandle] = extension; + } +} + +int slapi_register_object_extension( + const char *pluginname, + const char *objectname, + slapi_extension_constructor_fnptr constructor, + slapi_extension_destructor_fnptr destructor, + int *objecttype, + int *extensionhandle) +{ + int rc; + slapi_extension_t type; + struct slapi_registered_extension *re; + + ldap_pvt_thread_mutex_lock( ®istered_extensions.mutex ); + + rc = map_extension_type( objectname, &type ); + if ( rc != 0 ) { + ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex ); + return rc; + } + + *objecttype = (int)type; + + re = ®istered_extensions.extensions[*objecttype]; + + *extensionhandle = re->count; + + if ( re->active ) { + /* can't add new extensions after objects have been created */ + ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex ); + return -1; + } + + re->count++; + + if ( re->constructors == NULL ) { + re->constructors = (slapi_extension_constructor_fnptr *)slapi_ch_calloc( re->count, + sizeof( slapi_extension_constructor_fnptr ) ); + } else { + re->constructors = (slapi_extension_constructor_fnptr *)slapi_ch_realloc( (char *)re->constructors, + re->count * sizeof( slapi_extension_constructor_fnptr ) ); + } + re->constructors[*extensionhandle] = constructor; + + if ( re->destructors == NULL ) { + re->destructors = (slapi_extension_destructor_fnptr *)slapi_ch_calloc( re->count, + sizeof( slapi_extension_destructor_fnptr ) ); + } else { + re->destructors = (slapi_extension_destructor_fnptr *)slapi_ch_realloc( (char *)re->destructors, + re->count * sizeof( slapi_extension_destructor_fnptr ) ); + } + re->destructors[*extensionhandle] = destructor; + + ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex ); + + return 0; +} + +int slapi_int_create_object_extensions(int objecttype, void *object) +{ + int i; + struct slapi_extension_block *eblock; + void **peblock; + void *parent; + + switch ((slapi_extension_t) objecttype) { + case SLAPI_X_EXT_CONNECTION: + peblock = &(((Connection *)object)->c_extensions); + parent = NULL; + break; + case SLAPI_X_EXT_OPERATION: + peblock = &(((Operation *)object)->o_hdr->oh_extensions); + parent = ((Operation *)object)->o_conn; + break; + default: + return -1; + break; + } + + *peblock = NULL; + + ldap_pvt_thread_mutex_lock( ®istered_extensions.mutex ); + if ( registered_extensions.extensions[objecttype].active == 0 ) { + /* + * once we've created some extensions, no new extensions can + * be registered. + */ + registered_extensions.extensions[objecttype].active = 1; + } + ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex ); + + eblock = (struct slapi_extension_block *)slapi_ch_calloc( 1, sizeof(*eblock) ); + + if ( registered_extensions.extensions[objecttype].count ) { + eblock->extensions = (void **)slapi_ch_calloc( registered_extensions.extensions[objecttype].count, sizeof(void *) ); + for ( i = 0; i < registered_extensions.extensions[objecttype].count; i++ ) { + new_extension( eblock, objecttype, object, parent, i ); + } + } else { + eblock->extensions = NULL; + } + + *peblock = eblock; + + return 0; +} + +int slapi_int_free_object_extensions(int objecttype, void *object) +{ + int i; + struct slapi_extension_block *eblock; + void **peblock; + void *parent; + + switch ((slapi_extension_t) objecttype) { + case SLAPI_X_EXT_CONNECTION: + peblock = &(((Connection *)object)->c_extensions); + parent = NULL; + break; + case SLAPI_X_EXT_OPERATION: + peblock = &(((Operation *)object)->o_hdr->oh_extensions); + parent = ((Operation *)object)->o_conn; + break; + default: + return -1; + break; + } + + eblock = (struct slapi_extension_block *)*peblock; + + if ( eblock->extensions != NULL ) { + for ( i = registered_extensions.extensions[objecttype].count - 1; i >= 0; --i ) { + free_extension( eblock, objecttype, object, parent, i ); + } + + slapi_ch_free( (void **)&eblock->extensions ); + } + + slapi_ch_free( peblock ); + + return 0; +} + +/* for reusable object types */ +int slapi_int_clear_object_extensions(int objecttype, void *object) +{ + int i; + struct slapi_extension_block *eblock; + void *parent; + + if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) { + return -1; + } + + if ( eblock->extensions == NULL ) { + /* no extensions */ + return 0; + } + + for ( i = registered_extensions.extensions[objecttype].count - 1; i >= 0; --i ) { + free_extension( eblock, objecttype, object, parent, i ); + } + + for ( i = 0; i < registered_extensions.extensions[objecttype].count; i++ ) { + new_extension( eblock, objecttype, object, parent, i ); + } + + return 0; +} + +int slapi_int_init_object_extensions(void) +{ + memset( ®istered_extensions, 0, sizeof( registered_extensions ) ); + + if ( ldap_pvt_thread_mutex_init( ®istered_extensions.mutex ) != 0 ) { + return -1; + } + + return 0; +} + +#endif /* LDAP_SLAPI */ diff --git a/servers/slapd/slapi/slapi_ops.c b/servers/slapd/slapi/slapi_ops.c new file mode 100644 index 0000000..831562d --- /dev/null +++ b/servers/slapd/slapi/slapi_ops.c @@ -0,0 +1,956 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2002-2021 The OpenLDAP Foundation. + * Portions Copyright 1997,2002-2003 IBM Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by IBM Corporation for use in + * IBM products and subsequently ported to OpenLDAP Software by + * Steve Omrani. Additional significant contributors include: + * Luke Howard + */ + +#include "portable.h" + +#include <ac/string.h> +#include <ac/stdarg.h> +#include <ac/ctype.h> +#include <ac/unistd.h> + +#include <slap.h> +#include <lber_pvt.h> +#include <slapi.h> + +#ifdef LDAP_SLAPI + +static struct Listener slapi_listener = { + BER_BVC("slapi://"), + BER_BVC("slapi://") +}; + +static LDAPControl ** +slapi_int_dup_controls( LDAPControl **controls ) +{ + LDAPControl **c; + size_t i; + + if ( controls == NULL ) + return NULL; + + for ( i = 0; controls[i] != NULL; i++ ) + ; + + c = (LDAPControl **) slapi_ch_calloc( i + 1, sizeof(LDAPControl *) ); + + for ( i = 0; controls[i] != NULL; i++ ) { + c[i] = slapi_dup_control( controls[i] ); + } + + return c; +} + +static int +slapi_int_result( + Operation *op, + SlapReply *rs ) +{ + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + plugin_result_callback prc = NULL; + void *callback_data = NULL; + LDAPControl **ctrls = NULL; + + assert( pb != NULL ); + + slapi_pblock_get( pb, SLAPI_X_INTOP_RESULT_CALLBACK, (void **)&prc ); + slapi_pblock_get( pb, SLAPI_X_INTOP_CALLBACK_DATA, &callback_data ); + + /* we need to duplicate controls because they might go out of scope */ + ctrls = slapi_int_dup_controls( rs->sr_ctrls ); + slapi_pblock_set( pb, SLAPI_RESCONTROLS, ctrls ); + + if ( prc != NULL ) { + (*prc)( rs->sr_err, callback_data ); + } + + return rs->sr_err; +} + +static int +slapi_int_search_entry( + Operation *op, + SlapReply *rs ) +{ + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + plugin_search_entry_callback psec = NULL; + void *callback_data = NULL; + int rc = LDAP_SUCCESS; + + assert( pb != NULL ); + + slapi_pblock_get( pb, SLAPI_X_INTOP_SEARCH_ENTRY_CALLBACK, (void **)&psec ); + slapi_pblock_get( pb, SLAPI_X_INTOP_CALLBACK_DATA, &callback_data ); + + if ( psec != NULL ) { + rc = (*psec)( rs->sr_entry, callback_data ); + } + + return rc; +} + +static int +slapi_int_search_reference( + Operation *op, + SlapReply *rs ) +{ + int i, rc = LDAP_SUCCESS; + plugin_referral_entry_callback prec = NULL; + void *callback_data = NULL; + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + + assert( pb != NULL ); + + slapi_pblock_get( pb, SLAPI_X_INTOP_REFERRAL_ENTRY_CALLBACK, (void **)&prec ); + slapi_pblock_get( pb, SLAPI_X_INTOP_CALLBACK_DATA, &callback_data ); + + if ( prec != NULL ) { + for ( i = 0; rs->sr_ref[i].bv_val != NULL; i++ ) { + rc = (*prec)( rs->sr_ref[i].bv_val, callback_data ); + if ( rc != LDAP_SUCCESS ) { + break; + } + } + } + + return rc; +} + +int +slapi_int_response( Slapi_Operation *op, SlapReply *rs ) +{ + int rc; + + switch ( rs->sr_type ) { + case REP_RESULT: + rc = slapi_int_result( op, rs ); + break; + case REP_SEARCH: + rc = slapi_int_search_entry( op, rs ); + break; + case REP_SEARCHREF: + rc = slapi_int_search_reference( op, rs ); + break; + default: + rc = LDAP_OTHER; + break; + } + + assert( rc != SLAP_CB_CONTINUE ); /* never try to send a wire response */ + + return rc; +} + +static int +slapi_int_get_ctrls( Slapi_PBlock *pb ) +{ + LDAPControl **c; + int rc = LDAP_SUCCESS; + + if ( pb->pb_op->o_ctrls != NULL ) { + for ( c = pb->pb_op->o_ctrls; *c != NULL; c++ ) { + rc = slap_parse_ctrl( pb->pb_op, pb->pb_rs, *c, &pb->pb_rs->sr_text ); + if ( rc != LDAP_SUCCESS ) + break; + } + } + + return rc; +} + +void +slapi_int_connection_init_pb( Slapi_PBlock *pb, ber_tag_t tag ) +{ + Connection *conn; + Operation *op; + ber_len_t max = sockbuf_max_incoming; + + conn = (Connection *) slapi_ch_calloc( 1, sizeof(Connection) ); + + LDAP_STAILQ_INIT( &conn->c_pending_ops ); + + op = (Operation *) slapi_ch_calloc( 1, sizeof(OperationBuffer) ); + op->o_hdr = &((OperationBuffer *) op)->ob_hdr; + op->o_controls = ((OperationBuffer *) op)->ob_controls; + + op->o_callback = (slap_callback *) slapi_ch_calloc( 1, sizeof(slap_callback) ); + op->o_callback->sc_response = slapi_int_response; + op->o_callback->sc_cleanup = NULL; + op->o_callback->sc_private = pb; + op->o_callback->sc_next = NULL; + + conn->c_pending_ops.stqh_first = op; + + /* connection object authorization information */ + conn->c_authtype = LDAP_AUTH_NONE; + BER_BVZERO( &conn->c_authmech ); + BER_BVZERO( &conn->c_dn ); + BER_BVZERO( &conn->c_ndn ); + + conn->c_listener = &slapi_listener; + ber_dupbv( &conn->c_peer_domain, (struct berval *)&slap_unknown_bv ); + ber_dupbv( &conn->c_peer_name, (struct berval *)&slap_unknown_bv ); + + LDAP_STAILQ_INIT( &conn->c_ops ); + + BER_BVZERO( &conn->c_sasl_bind_mech ); + conn->c_sasl_authctx = NULL; + conn->c_sasl_sockctx = NULL; + conn->c_sasl_extra = NULL; + + conn->c_sb = ber_sockbuf_alloc(); + + ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); + + conn->c_currentber = NULL; + + /* should check status of thread calls */ + ldap_pvt_thread_mutex_init( &conn->c_mutex ); + ldap_pvt_thread_mutex_init( &conn->c_write1_mutex ); + ldap_pvt_thread_mutex_init( &conn->c_write2_mutex ); + ldap_pvt_thread_cond_init( &conn->c_write1_cv ); + ldap_pvt_thread_cond_init( &conn->c_write2_cv ); + + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + + conn->c_n_ops_received = 0; + conn->c_n_ops_executing = 0; + conn->c_n_ops_pending = 0; + conn->c_n_ops_completed = 0; + + conn->c_n_get = 0; + conn->c_n_read = 0; + conn->c_n_write = 0; + + conn->c_protocol = LDAP_VERSION3; + + conn->c_activitytime = conn->c_starttime = slap_get_time(); + + /* + * A real connection ID is required, because syncrepl associates + * pending CSNs with unique ( connection, operation ) tuples. + * Setting a fake connection ID will cause slap_get_commit_csn() + * to return a stale value. + */ + connection_assign_nextid( conn ); + + conn->c_conn_state = 0x01; /* SLAP_C_ACTIVE */ + conn->c_struct_state = 0x02; /* SLAP_C_USED */ + + conn->c_ssf = conn->c_transport_ssf = local_ssf; + conn->c_tls_ssf = 0; + + backend_connection_init( conn ); + + conn->c_send_ldap_result = slap_send_ldap_result; + conn->c_send_search_entry = slap_send_search_entry; + conn->c_send_ldap_extended = slap_send_ldap_extended; + conn->c_send_search_reference = slap_send_search_reference; + + /* operation object */ + op->o_tag = tag; + op->o_protocol = LDAP_VERSION3; + BER_BVZERO( &op->o_authmech ); + op->o_time = slap_get_time(); + op->o_do_not_cache = 1; + op->o_threadctx = ldap_pvt_thread_pool_context(); + op->o_tmpmemctx = NULL; + op->o_tmpmfuncs = &ch_mfuncs; + op->o_conn = conn; + op->o_connid = conn->c_connid; + op->o_bd = frontendDB; + + /* extensions */ + slapi_int_create_object_extensions( SLAPI_X_EXT_OPERATION, op ); + slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, conn ); + + pb->pb_rs = (SlapReply *)slapi_ch_calloc( 1, sizeof(SlapReply) ); + pb->pb_op = op; + pb->pb_conn = conn; + pb->pb_intop = 1; + + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); +} + +static void +slapi_int_set_operation_dn( Slapi_PBlock *pb ) +{ + Backend *be; + Operation *op = pb->pb_op; + + if ( BER_BVISNULL( &op->o_ndn ) ) { + /* set to root DN */ + be = select_backend( &op->o_req_ndn, 1 ); + if ( be != NULL ) { + ber_dupbv( &op->o_dn, &be->be_rootdn ); + ber_dupbv( &op->o_ndn, &be->be_rootndn ); + } + } +} + +void +slapi_int_connection_done_pb( Slapi_PBlock *pb ) +{ + Connection *conn; + Operation *op; + + PBLOCK_ASSERT_INTOP( pb, 0 ); + + conn = pb->pb_conn; + op = pb->pb_op; + + /* free allocated DNs */ + if ( !BER_BVISNULL( &op->o_dn ) ) + op->o_tmpfree( op->o_dn.bv_val, op->o_tmpmemctx ); + if ( !BER_BVISNULL( &op->o_ndn ) ) + op->o_tmpfree( op->o_ndn.bv_val, op->o_tmpmemctx ); + + if ( !BER_BVISNULL( &op->o_req_dn ) ) + op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); + if ( !BER_BVISNULL( &op->o_req_ndn ) ) + op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); + + switch ( op->o_tag ) { + case LDAP_REQ_MODRDN: + if ( !BER_BVISNULL( &op->orr_newrdn )) + op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx ); + if ( !BER_BVISNULL( &op->orr_nnewrdn )) + op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx ); + if ( op->orr_newSup != NULL ) { + assert( !BER_BVISNULL( op->orr_newSup ) ); + op->o_tmpfree( op->orr_newSup->bv_val, op->o_tmpmemctx ); + op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx ); + } + if ( op->orr_nnewSup != NULL ) { + assert( !BER_BVISNULL( op->orr_nnewSup ) ); + op->o_tmpfree( op->orr_nnewSup->bv_val, op->o_tmpmemctx ); + op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx ); + } + slap_mods_free( op->orr_modlist, 1 ); + break; + case LDAP_REQ_ADD: + slap_mods_free( op->ora_modlist, 0 ); + break; + case LDAP_REQ_MODIFY: + slap_mods_free( op->orm_modlist, 1 ); + break; + case LDAP_REQ_SEARCH: + if ( op->ors_attrs != NULL ) { + op->o_tmpfree( op->ors_attrs, op->o_tmpmemctx ); + op->ors_attrs = NULL; + } + break; + default: + break; + } + + slapi_ch_free_string( &conn->c_authmech.bv_val ); + slapi_ch_free_string( &conn->c_dn.bv_val ); + slapi_ch_free_string( &conn->c_ndn.bv_val ); + slapi_ch_free_string( &conn->c_peer_domain.bv_val ); + slapi_ch_free_string( &conn->c_peer_name.bv_val ); + + if ( conn->c_sb != NULL ) { + ber_sockbuf_free( conn->c_sb ); + } + + slapi_int_free_object_extensions( SLAPI_X_EXT_OPERATION, op ); + slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION, conn ); + + slapi_ch_free( (void **)&pb->pb_op->o_callback ); + slapi_ch_free( (void **)&pb->pb_op ); + slapi_ch_free( (void **)&pb->pb_conn ); + slapi_ch_free( (void **)&pb->pb_rs ); +} + +static int +slapi_int_func_internal_pb( Slapi_PBlock *pb, slap_operation_t which ) +{ + BI_op_bind **func; + SlapReply *rs = pb->pb_rs; + int rc; + + PBLOCK_ASSERT_INTOP( pb, 0 ); + + rc = slapi_int_get_ctrls( pb ); + if ( rc != LDAP_SUCCESS ) { + rs->sr_err = rc; + return rc; + } + + pb->pb_op->o_bd = frontendDB; + func = &frontendDB->be_bind; + + return func[which]( pb->pb_op, pb->pb_rs ); +} + +int +slapi_delete_internal_pb( Slapi_PBlock *pb ) +{ + if ( pb == NULL ) { + return -1; + } + + PBLOCK_ASSERT_INTOP( pb, LDAP_REQ_DELETE ); + + slapi_int_func_internal_pb( pb, op_delete ); + + return 0; +} + +int +slapi_add_internal_pb( Slapi_PBlock *pb ) +{ + SlapReply *rs; + Slapi_Entry *entry_orig = NULL; + OpExtraDB oex; + int rc; + + if ( pb == NULL ) { + return -1; + } + + PBLOCK_ASSERT_INTOP( pb, LDAP_REQ_ADD ); + + rs = pb->pb_rs; + + entry_orig = pb->pb_op->ora_e; + pb->pb_op->ora_e = NULL; + + /* + * The caller can specify a new entry, or a target DN and set + * of modifications, but not both. + */ + if ( entry_orig != NULL ) { + if ( pb->pb_op->ora_modlist != NULL || !BER_BVISNULL( &pb->pb_op->o_req_ndn )) { + rs->sr_err = LDAP_PARAM_ERROR; + goto cleanup; + } + + assert( BER_BVISNULL( &pb->pb_op->o_req_dn ) ); /* shouldn't get set */ + ber_dupbv( &pb->pb_op->o_req_dn, &entry_orig->e_name ); + ber_dupbv( &pb->pb_op->o_req_ndn, &entry_orig->e_nname ); + } else if ( pb->pb_op->ora_modlist == NULL || BER_BVISNULL( &pb->pb_op->o_req_ndn )) { + rs->sr_err = LDAP_PARAM_ERROR; + goto cleanup; + } + + pb->pb_op->ora_e = (Entry *)slapi_ch_calloc( 1, sizeof(Entry) ); + ber_dupbv( &pb->pb_op->ora_e->e_name, &pb->pb_op->o_req_dn ); + ber_dupbv( &pb->pb_op->ora_e->e_nname, &pb->pb_op->o_req_ndn ); + + if ( entry_orig != NULL ) { + assert( pb->pb_op->ora_modlist == NULL ); + + rs->sr_err = slap_entry2mods( entry_orig, &pb->pb_op->ora_modlist, + &rs->sr_text, pb->pb_textbuf, sizeof( pb->pb_textbuf ) ); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto cleanup; + } + } else { + assert( pb->pb_op->ora_modlist != NULL ); + } + + rs->sr_err = slap_mods_check( pb->pb_op, pb->pb_op->ora_modlist, &rs->sr_text, + pb->pb_textbuf, sizeof( pb->pb_textbuf ), NULL ); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto cleanup; + } + + /* Duplicate the values, because we may call slapi_entry_free() */ + rs->sr_err = slap_mods2entry( pb->pb_op->ora_modlist, &pb->pb_op->ora_e, + 1, 0, &rs->sr_text, pb->pb_textbuf, sizeof( pb->pb_textbuf ) ); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto cleanup; + } + + oex.oe.oe_key = (void *)do_add; + oex.oe_db = NULL; + LDAP_SLIST_INSERT_HEAD(&pb->pb_op->o_extra, &oex.oe, oe_next); + rc = slapi_int_func_internal_pb( pb, op_add ); + LDAP_SLIST_REMOVE(&pb->pb_op->o_extra, &oex.oe, OpExtra, oe_next); + + if ( !rc ) { + if ( pb->pb_op->ora_e != NULL && oex.oe_db != NULL ) { + BackendDB *bd = pb->pb_op->o_bd; + + pb->pb_op->o_bd = oex.oe_db; + be_entry_release_w( pb->pb_op, pb->pb_op->ora_e ); + pb->pb_op->ora_e = NULL; + pb->pb_op->o_bd = bd; + } + } + +cleanup: + + if ( pb->pb_op->ora_e != NULL ) { + slapi_entry_free( pb->pb_op->ora_e ); + pb->pb_op->ora_e = NULL; + } + if ( entry_orig != NULL ) { + pb->pb_op->ora_e = entry_orig; + slap_mods_free( pb->pb_op->ora_modlist, 1 ); + pb->pb_op->ora_modlist = NULL; + } + + return 0; +} + +int +slapi_modrdn_internal_pb( Slapi_PBlock *pb ) +{ + if ( pb == NULL ) { + return -1; + } + + PBLOCK_ASSERT_INTOP( pb, LDAP_REQ_MODRDN ); + + if ( BER_BVISEMPTY( &pb->pb_op->o_req_ndn ) ) { + pb->pb_rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + goto cleanup; + } + + slapi_int_func_internal_pb( pb, op_modrdn ); + +cleanup: + + return 0; +} + +int +slapi_modify_internal_pb( Slapi_PBlock *pb ) +{ + SlapReply *rs; + + if ( pb == NULL ) { + return -1; + } + + PBLOCK_ASSERT_INTOP( pb, LDAP_REQ_MODIFY ); + + rs = pb->pb_rs; + + if ( pb->pb_op->orm_modlist == NULL ) { + rs->sr_err = LDAP_PARAM_ERROR; + goto cleanup; + } + + if ( BER_BVISEMPTY( &pb->pb_op->o_req_ndn ) ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + goto cleanup; + } + + rs->sr_err = slap_mods_check( pb->pb_op, pb->pb_op->orm_modlist, + &rs->sr_text, pb->pb_textbuf, sizeof( pb->pb_textbuf ), NULL ); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto cleanup; + } + + slapi_int_func_internal_pb( pb, op_modify ); + +cleanup: + + return 0; +} + +static int +slapi_int_search_entry_callback( Slapi_Entry *entry, void *callback_data ) +{ + int nentries = 0, i = 0; + Slapi_Entry **head = NULL, **tp; + Slapi_PBlock *pb = (Slapi_PBlock *)callback_data; + + PBLOCK_ASSERT_INTOP( pb, LDAP_REQ_SEARCH ); + + entry = slapi_entry_dup( entry ); + if ( entry == NULL ) { + return LDAP_NO_MEMORY; + } + + slapi_pblock_get( pb, SLAPI_NENTRIES, &nentries ); + slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &head ); + + i = nentries + 1; + if ( nentries == 0 ) { + tp = (Slapi_Entry **)slapi_ch_malloc( 2 * sizeof(Slapi_Entry *) ); + if ( tp == NULL ) { + slapi_entry_free( entry ); + return LDAP_NO_MEMORY; + } + + tp[0] = entry; + } else { + tp = (Slapi_Entry **)slapi_ch_realloc( (char *)head, + sizeof(Slapi_Entry *) * ( i + 1 ) ); + if ( tp == NULL ) { + slapi_entry_free( entry ); + return LDAP_NO_MEMORY; + } + tp[i - 1] = entry; + } + tp[i] = NULL; + + slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, (void *)tp ); + slapi_pblock_set( pb, SLAPI_NENTRIES, (void *)&i ); + + return LDAP_SUCCESS; +} + +int +slapi_search_internal_pb( Slapi_PBlock *pb ) +{ + return slapi_search_internal_callback_pb( pb, + (void *)pb, + NULL, + slapi_int_search_entry_callback, + NULL ); +} + +int +slapi_search_internal_callback_pb( Slapi_PBlock *pb, + void *callback_data, + plugin_result_callback prc, + plugin_search_entry_callback psec, + plugin_referral_entry_callback prec ) +{ + int free_filter = 0; + SlapReply *rs; + + if ( pb == NULL ) { + return -1; + } + + PBLOCK_ASSERT_INTOP( pb, LDAP_REQ_SEARCH ); + + rs = pb->pb_rs; + + /* search callback and arguments */ + slapi_pblock_set( pb, SLAPI_X_INTOP_RESULT_CALLBACK, (void *)prc ); + slapi_pblock_set( pb, SLAPI_X_INTOP_SEARCH_ENTRY_CALLBACK, (void *)psec ); + slapi_pblock_set( pb, SLAPI_X_INTOP_REFERRAL_ENTRY_CALLBACK, (void *)prec ); + slapi_pblock_set( pb, SLAPI_X_INTOP_CALLBACK_DATA, (void *)callback_data ); + + if ( BER_BVISEMPTY( &pb->pb_op->ors_filterstr )) { + rs->sr_err = LDAP_PARAM_ERROR; + goto cleanup; + } + + if ( pb->pb_op->ors_filter == NULL ) { + pb->pb_op->ors_filter = slapi_str2filter( pb->pb_op->ors_filterstr.bv_val ); + if ( pb->pb_op->ors_filter == NULL ) { + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto cleanup; + } + + free_filter = 1; + } + + slapi_int_func_internal_pb( pb, op_search ); + +cleanup: + if ( free_filter ) { + slapi_filter_free( pb->pb_op->ors_filter, 1 ); + pb->pb_op->ors_filter = NULL; + } + + slapi_pblock_delete_param( pb, SLAPI_X_INTOP_RESULT_CALLBACK ); + slapi_pblock_delete_param( pb, SLAPI_X_INTOP_SEARCH_ENTRY_CALLBACK ); + slapi_pblock_delete_param( pb, SLAPI_X_INTOP_REFERRAL_ENTRY_CALLBACK ); + slapi_pblock_delete_param( pb, SLAPI_X_INTOP_CALLBACK_DATA ); + + return 0; +} + +/* Wrappers for old API */ + +void +slapi_search_internal_set_pb( Slapi_PBlock *pb, + const char *base, + int scope, + const char *filter, + char **attrs, + int attrsonly, + LDAPControl **controls, + const char *uniqueid, + Slapi_ComponentId *plugin_identity, + int operation_flags ) +{ + int no_limit = SLAP_NO_LIMIT; + int deref = LDAP_DEREF_NEVER; + + slapi_int_connection_init_pb( pb, LDAP_REQ_SEARCH ); + slapi_pblock_set( pb, SLAPI_SEARCH_TARGET, (void *)base ); + slapi_pblock_set( pb, SLAPI_SEARCH_SCOPE, (void *)&scope ); + slapi_pblock_set( pb, SLAPI_SEARCH_FILTER, (void *)0 ); + slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, (void *)filter ); + slapi_pblock_set( pb, SLAPI_SEARCH_ATTRS, (void *)attrs ); + slapi_pblock_set( pb, SLAPI_SEARCH_ATTRSONLY, (void *)&attrsonly ); + slapi_pblock_set( pb, SLAPI_REQCONTROLS, (void *)controls ); + slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID, (void *)uniqueid ); + slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity ); + slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS, (void *)&operation_flags ); + slapi_pblock_set( pb, SLAPI_SEARCH_DEREF, (void *)&deref ); + slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, (void *)&no_limit ); + slapi_pblock_set( pb, SLAPI_SEARCH_TIMELIMIT, (void *)&no_limit ); + + slapi_int_set_operation_dn( pb ); +} + +Slapi_PBlock * +slapi_search_internal( + char *ldn, + int scope, + char *filStr, + LDAPControl **controls, + char **attrs, + int attrsonly ) +{ + Slapi_PBlock *pb; + + pb = slapi_pblock_new(); + + slapi_search_internal_set_pb( pb, ldn, scope, filStr, + attrs, attrsonly, + controls, NULL, NULL, 0 ); + + slapi_search_internal_pb( pb ); + + return pb; +} + +void +slapi_modify_internal_set_pb( Slapi_PBlock *pb, + const char *dn, + LDAPMod **mods, + LDAPControl **controls, + const char *uniqueid, + Slapi_ComponentId *plugin_identity, + int operation_flags ) +{ + slapi_int_connection_init_pb( pb, LDAP_REQ_MODIFY ); + slapi_pblock_set( pb, SLAPI_MODIFY_TARGET, (void *)dn ); + slapi_pblock_set( pb, SLAPI_MODIFY_MODS, (void *)mods ); + slapi_pblock_set( pb, SLAPI_REQCONTROLS, (void *)controls ); + slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID, (void *)uniqueid ); + slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity ); + slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS, (void *)&operation_flags ); + slapi_int_set_operation_dn( pb ); +} + +/* Function : slapi_modify_internal + * + * Description: Plugin functions call this routine to modify an entry + * in the backend directly + * Return values : LDAP_SUCCESS + * LDAP_PARAM_ERROR + * LDAP_NO_MEMORY + * LDAP_OTHER + * LDAP_UNWILLING_TO_PERFORM +*/ +Slapi_PBlock * +slapi_modify_internal( + char *ldn, + LDAPMod **mods, + LDAPControl **controls, + int log_change ) +{ + Slapi_PBlock *pb; + + pb = slapi_pblock_new(); + + slapi_modify_internal_set_pb( pb, ldn, mods, controls, NULL, NULL, 0 ); + slapi_pblock_set( pb, SLAPI_LOG_OPERATION, (void *)&log_change ); + slapi_modify_internal_pb( pb ); + + return pb; +} + +int +slapi_add_internal_set_pb( Slapi_PBlock *pb, + const char *dn, + LDAPMod **attrs, + LDAPControl **controls, + Slapi_ComponentId *plugin_identity, + int operation_flags ) +{ + slapi_int_connection_init_pb( pb, LDAP_REQ_ADD ); + slapi_pblock_set( pb, SLAPI_ADD_TARGET, (void *)dn ); + slapi_pblock_set( pb, SLAPI_MODIFY_MODS, (void *)attrs ); + slapi_pblock_set( pb, SLAPI_REQCONTROLS, (void *)controls ); + slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity ); + slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS, (void *)&operation_flags ); + slapi_int_set_operation_dn( pb ); + + return 0; +} + +Slapi_PBlock * +slapi_add_internal( + char * dn, + LDAPMod **attrs, + LDAPControl **controls, + int log_change ) +{ + Slapi_PBlock *pb; + + pb = slapi_pblock_new(); + + slapi_add_internal_set_pb( pb, dn, attrs, controls, NULL, 0); + slapi_pblock_set( pb, SLAPI_LOG_OPERATION, (void *)&log_change ); + slapi_add_internal_pb( pb ); + + return pb; +} + +void +slapi_add_entry_internal_set_pb( Slapi_PBlock *pb, + Slapi_Entry *e, + LDAPControl **controls, + Slapi_ComponentId *plugin_identity, + int operation_flags ) +{ + slapi_int_connection_init_pb( pb, LDAP_REQ_ADD ); + slapi_pblock_set( pb, SLAPI_ADD_ENTRY, (void *)e ); + slapi_pblock_set( pb, SLAPI_REQCONTROLS, (void *)controls ); + slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity ); + slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS, (void *)&operation_flags ); + slapi_int_set_operation_dn( pb ); +} + +Slapi_PBlock * +slapi_add_entry_internal( + Slapi_Entry *e, + LDAPControl **controls, + int log_change ) +{ + Slapi_PBlock *pb; + + pb = slapi_pblock_new(); + + slapi_add_entry_internal_set_pb( pb, e, controls, NULL, 0 ); + slapi_pblock_set( pb, SLAPI_LOG_OPERATION, (void *)&log_change ); + slapi_add_internal_pb( pb ); + + return pb; +} + +void +slapi_rename_internal_set_pb( Slapi_PBlock *pb, + const char *olddn, + const char *newrdn, + const char *newsuperior, + int deloldrdn, + LDAPControl **controls, + const char *uniqueid, + Slapi_ComponentId *plugin_identity, + int operation_flags ) +{ + slapi_int_connection_init_pb( pb, LDAP_REQ_MODRDN ); + slapi_pblock_set( pb, SLAPI_MODRDN_TARGET, (void *)olddn ); + slapi_pblock_set( pb, SLAPI_MODRDN_NEWRDN, (void *)newrdn ); + slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR, (void *)newsuperior ); + slapi_pblock_set( pb, SLAPI_MODRDN_DELOLDRDN, (void *)&deloldrdn ); + slapi_pblock_set( pb, SLAPI_REQCONTROLS, (void *)controls ); + slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID, (void *)uniqueid ); + slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity ); + slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS, (void *)&operation_flags ); + slap_modrdn2mods( pb->pb_op, pb->pb_rs ); + slapi_int_set_operation_dn( pb ); +} + +/* Function : slapi_modrdn_internal + * + * Description : Plugin functions call this routine to modify the rdn + * of an entry in the backend directly + * Return values : LDAP_SUCCESS + * LDAP_PARAM_ERROR + * LDAP_NO_MEMORY + * LDAP_OTHER + * LDAP_UNWILLING_TO_PERFORM + * + * NOTE: This function does not support the "newSuperior" option from LDAP V3. + */ +Slapi_PBlock * +slapi_modrdn_internal( + char *olddn, + char *lnewrdn, + int deloldrdn, + LDAPControl **controls, + int log_change ) +{ + Slapi_PBlock *pb; + + pb = slapi_pblock_new (); + + slapi_rename_internal_set_pb( pb, olddn, lnewrdn, NULL, + deloldrdn, controls, NULL, NULL, 0 ); + slapi_pblock_set( pb, SLAPI_LOG_OPERATION, (void *)&log_change ); + slapi_modrdn_internal_pb( pb ); + + return pb; +} + +void +slapi_delete_internal_set_pb( Slapi_PBlock *pb, + const char *dn, + LDAPControl **controls, + const char *uniqueid, + Slapi_ComponentId *plugin_identity, + int operation_flags ) +{ + slapi_int_connection_init_pb( pb, LDAP_REQ_DELETE ); + slapi_pblock_set( pb, SLAPI_TARGET_DN, (void *)dn ); + slapi_pblock_set( pb, SLAPI_REQCONTROLS, (void *)controls ); + slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID, (void *)uniqueid ); + slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity ); + slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS, (void *)&operation_flags ); + slapi_int_set_operation_dn( pb ); +} + +/* Function : slapi_delete_internal + * + * Description : Plugin functions call this routine to delete an entry + * in the backend directly + * Return values : LDAP_SUCCESS + * LDAP_PARAM_ERROR + * LDAP_NO_MEMORY + * LDAP_OTHER + * LDAP_UNWILLING_TO_PERFORM +*/ +Slapi_PBlock * +slapi_delete_internal( + char *ldn, + LDAPControl **controls, + int log_change ) +{ + Slapi_PBlock *pb; + + pb = slapi_pblock_new(); + + slapi_delete_internal_set_pb( pb, ldn, controls, NULL, NULL, 0 ); + slapi_pblock_set( pb, SLAPI_LOG_OPERATION, (void *)&log_change ); + slapi_delete_internal_pb( pb ); + + return pb; +} + +#endif /* LDAP_SLAPI */ + diff --git a/servers/slapd/slapi/slapi_overlay.c b/servers/slapd/slapi/slapi_overlay.c new file mode 100644 index 0000000..88e7f1c --- /dev/null +++ b/servers/slapd/slapi/slapi_overlay.c @@ -0,0 +1,952 @@ +/* slapi_overlay.c - SLAPI overlay */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2001-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Luke Howard for inclusion + * in OpenLDAP Software. + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/string.h> +#include <ac/socket.h> + +#include "slap.h" +#include "slapi.h" +#include "config.h" + +#ifdef LDAP_SLAPI + +static slap_overinst slapi; +static int slapi_over_initialized = 0; + +static int slapi_over_response( Operation *op, SlapReply *rs ); +static int slapi_over_cleanup( Operation *op, SlapReply *rs ); + +static Slapi_PBlock * +slapi_over_pblock_new( Operation *op, SlapReply *rs ) +{ + Slapi_PBlock *pb; + + pb = slapi_pblock_new(); + pb->pb_op = op; + pb->pb_conn = op->o_conn; + pb->pb_rs = rs; + pb->pb_intop = 0; + + PBLOCK_ASSERT_OP( pb, op->o_tag ); + + return pb; +} + +static int +slapi_op_internal_p( Operation *op, SlapReply *rs, slap_callback *cb ) +{ + int internal_op = 0; + Slapi_PBlock *pb = NULL; + slap_callback *pcb; + + /* + * Abstraction violating check for SLAPI internal operations + * allows pblock to remain consistent when invoking internal + * op plugins + */ + for ( pcb = op->o_callback; pcb != NULL; pcb = pcb->sc_next ) { + if ( pcb->sc_response == slapi_int_response ) { + pb = (Slapi_PBlock *)pcb->sc_private; + PBLOCK_ASSERT_INTOP( pb, 0 ); + internal_op = 1; + break; + } + } + + if ( cb != NULL ) { + if ( pb == NULL ) { + pb = slapi_over_pblock_new( op, rs ); + } + + cb->sc_response = slapi_over_response; + cb->sc_cleanup = slapi_over_cleanup; + cb->sc_private = pb; + cb->sc_writewait = 0; + cb->sc_next = op->o_callback; + op->o_callback = cb; + } + + return internal_op; +} + +static int +slapi_over_compute_output( + computed_attr_context *c, + Slapi_Attr *attribute, + Slapi_Entry *entry +) +{ + Attribute **a; + AttributeDescription *desc; + SlapReply *rs; + + if ( c == NULL || attribute == NULL || entry == NULL ) { + return 0; + } + + rs = (SlapReply *)c->cac_private; + + assert( rs->sr_entry == entry ); + + desc = attribute->a_desc; + + if ( rs->sr_attrs == NULL ) { + /* All attrs request, skip operational attributes */ + if ( is_at_operational( desc->ad_type ) ) { + return 0; + } + } else { + /* Specific attributes requested */ + if ( is_at_operational( desc->ad_type ) ) { + if ( !SLAP_OPATTRS( rs->sr_attr_flags ) && + !ad_inlist( desc, rs->sr_attrs ) ) { + return 0; + } + } else { + if ( !SLAP_USERATTRS( rs->sr_attr_flags ) && + !ad_inlist( desc, rs->sr_attrs ) ) { + return 0; + } + } + } + + /* XXX perhaps we should check for existing attributes and merge */ + for ( a = &rs->sr_operational_attrs; *a != NULL; a = &(*a)->a_next ) + ; + + *a = slapi_attr_dup( attribute ); + + return 0; +} + +static int +slapi_over_aux_operational( Operation *op, SlapReply *rs ) +{ + /* Support for computed attribute plugins */ + computed_attr_context ctx; + AttributeName *anp; + + if ( slapi_op_internal_p( op, rs, NULL ) ) { + return SLAP_CB_CONTINUE; + } + + ctx.cac_pb = slapi_over_pblock_new( op, rs ); + ctx.cac_op = op; + ctx.cac_private = rs; + + if ( rs->sr_entry != NULL ) { + /* + * For each client requested attribute, call the plugins. + */ + if ( rs->sr_attrs != NULL ) { + for ( anp = rs->sr_attrs; anp->an_name.bv_val != NULL; anp++ ) { + if ( compute_evaluator( &ctx, anp->an_name.bv_val, + rs->sr_entry, slapi_over_compute_output ) == 1 ) { + break; + } + } + } else { + /* + * Technically we shouldn't be returning operational attributes + * when the user requested only user attributes. We'll let the + * plugin decide whether to be naughty or not. + */ + compute_evaluator( &ctx, "*", rs->sr_entry, slapi_over_compute_output ); + } + } + + slapi_pblock_destroy( ctx.cac_pb ); + + return SLAP_CB_CONTINUE; +} + +/* + * We need this function to call frontendDB (global) plugins before + * database plugins, if we are invoked by a slap_callback. + */ +static int +slapi_over_call_plugins( Slapi_PBlock *pb, int type ) +{ + int rc = 1; /* means no plugins called */ + Operation *op; + + PBLOCK_ASSERT_OP( pb, 0 ); + op = pb->pb_op; + + if ( !be_match( op->o_bd, frontendDB ) ) { + rc = slapi_int_call_plugins( frontendDB, type, pb ); + } + if ( rc >= 0 ) { + rc = slapi_int_call_plugins( op->o_bd, type, pb ); + } + + return rc; +} + +static int +slapi_over_search( Operation *op, SlapReply *rs, int type ) +{ + int rc; + Slapi_PBlock *pb; + + assert( rs->sr_type == REP_SEARCH || rs->sr_type == REP_SEARCHREF ); + + /* create a new pblock to not trample on result controls */ + pb = slapi_over_pblock_new( op, rs ); + + rc = slapi_over_call_plugins( pb, type ); + if ( rc >= 0 ) /* 1 means no plugins called */ + rc = SLAP_CB_CONTINUE; + else + rc = LDAP_SUCCESS; /* confusing: don't abort, but don't send */ + + slapi_pblock_destroy(pb); + + return rc; +} + +/* + * Call pre- and post-result plugins + */ +static int +slapi_over_result( Operation *op, SlapReply *rs, int type ) +{ + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + + assert( rs->sr_type == REP_RESULT || rs->sr_type == REP_SASL || rs->sr_type == REP_EXTENDED ); + + slapi_over_call_plugins( pb, type ); + + return SLAP_CB_CONTINUE; +} + + +static int +slapi_op_bind_callback( Operation *op, SlapReply *rs, int prc ) +{ + switch ( prc ) { + case SLAPI_BIND_SUCCESS: + /* Continue with backend processing */ + break; + case SLAPI_BIND_FAIL: + /* Failure, frontend (that's us) sends result */ + rs->sr_err = LDAP_INVALID_CREDENTIALS; + send_ldap_result( op, rs ); + return rs->sr_err; + break; + case SLAPI_BIND_ANONYMOUS: /* undocumented */ + default: /* plugin sent result or no plugins called */ + BER_BVZERO( &op->orb_edn ); + + if ( rs->sr_err == LDAP_SUCCESS ) { + /* + * Plugin will have called slapi_pblock_set(LDAP_CONN_DN) which + * will have set conn->c_dn and conn->c_ndn + */ + if ( BER_BVISNULL( &op->o_conn->c_ndn ) && prc == 1 ) { + /* No plugins were called; continue processing */ + return LDAP_SUCCESS; + } + ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); + if ( !BER_BVISEMPTY( &op->o_conn->c_ndn ) ) { + ber_len_t max = sockbuf_max_incoming_auth; + ber_sockbuf_ctrl( op->o_conn->c_sb, + LBER_SB_OPT_SET_MAX_INCOMING, &max ); + } + ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); + + /* log authorization identity */ + Statslog( LDAP_DEBUG_STATS, + "%s BIND dn=\"%s\" mech=%s (SLAPI) ssf=0\n", + op->o_log_prefix, + BER_BVISNULL( &op->o_conn->c_dn ) + ? "<empty>" : op->o_conn->c_dn.bv_val, + BER_BVISNULL( &op->orb_mech ) + ? "<empty>" : op->orb_mech.bv_val, 0, 0 ); + + return -1; + } + break; + } + + return rs->sr_err; +} + +static int +slapi_op_search_callback( Operation *op, SlapReply *rs, int prc ) +{ + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + Filter *f = op->ors_filter; + + /* check preoperation result code */ + if ( prc < 0 ) { + return rs->sr_err; + } + + rs->sr_err = LDAP_SUCCESS; + + if ( pb->pb_intop == 0 && + slapi_int_call_plugins( op->o_bd, SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN, pb ) == 0 ) { + /* + * The plugin can set the SLAPI_SEARCH_FILTER. + * SLAPI_SEARCH_STRFILER is not normative. + */ + if (f != op->ors_filter) { + op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); + filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); + } + } + + return LDAP_SUCCESS; +} + +struct slapi_op_info { + int soi_preop; /* preoperation plugin parameter */ + int soi_postop; /* postoperation plugin parameter */ + int soi_internal_preop; /* internal preoperation plugin parameter */ + int soi_internal_postop; /* internal postoperation plugin parameter */ + int (*soi_callback)(Operation *, SlapReply *, int); /* preoperation result handler */ +} slapi_op_dispatch_table[] = { + { + SLAPI_PLUGIN_PRE_BIND_FN, + SLAPI_PLUGIN_POST_BIND_FN, + SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN, + SLAPI_PLUGIN_INTERNAL_POST_BIND_FN, + slapi_op_bind_callback + }, + { + SLAPI_PLUGIN_PRE_UNBIND_FN, + SLAPI_PLUGIN_POST_UNBIND_FN, + SLAPI_PLUGIN_INTERNAL_PRE_UNBIND_FN, + SLAPI_PLUGIN_INTERNAL_POST_UNBIND_FN, + NULL + }, + { + SLAPI_PLUGIN_PRE_SEARCH_FN, + SLAPI_PLUGIN_POST_SEARCH_FN, + SLAPI_PLUGIN_INTERNAL_PRE_SEARCH_FN, + SLAPI_PLUGIN_INTERNAL_POST_SEARCH_FN, + slapi_op_search_callback + }, + { + SLAPI_PLUGIN_PRE_COMPARE_FN, + SLAPI_PLUGIN_POST_COMPARE_FN, + SLAPI_PLUGIN_INTERNAL_PRE_COMPARE_FN, + SLAPI_PLUGIN_INTERNAL_POST_COMPARE_FN, + NULL + }, + { + SLAPI_PLUGIN_PRE_MODIFY_FN, + SLAPI_PLUGIN_POST_MODIFY_FN, + SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN, + SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, + NULL + }, + { + SLAPI_PLUGIN_PRE_MODRDN_FN, + SLAPI_PLUGIN_POST_MODRDN_FN, + SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN, + SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, + NULL + }, + { + SLAPI_PLUGIN_PRE_ADD_FN, + SLAPI_PLUGIN_POST_ADD_FN, + SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN, + SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, + NULL + }, + { + SLAPI_PLUGIN_PRE_DELETE_FN, + SLAPI_PLUGIN_POST_DELETE_FN, + SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN, + SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, + NULL + }, + { + SLAPI_PLUGIN_PRE_ABANDON_FN, + SLAPI_PLUGIN_POST_ABANDON_FN, + SLAPI_PLUGIN_INTERNAL_PRE_ABANDON_FN, + SLAPI_PLUGIN_INTERNAL_POST_ABANDON_FN, + NULL + }, + { + 0, + 0, + 0, + 0, + NULL + } +}; + +slap_operation_t +slapi_tag2op( ber_tag_t tag ) +{ + slap_operation_t op; + + switch ( tag ) { + case LDAP_REQ_BIND: + op = op_bind; + break; + case LDAP_REQ_ADD: + op = op_add; + break; + case LDAP_REQ_DELETE: + op = op_delete; + break; + case LDAP_REQ_MODRDN: + op = op_modrdn; + break; + case LDAP_REQ_MODIFY: + op = op_modify; + break; + case LDAP_REQ_COMPARE: + op = op_compare; + break; + case LDAP_REQ_SEARCH: + op = op_search; + break; + case LDAP_REQ_UNBIND: + op = op_unbind; + break; + default: + op = op_last; + break; + } + + return op; +} + +/* Add SLAPI_RESCONTROLS to rs->sr_ctrls, with care, because + * rs->sr_ctrls could be allocated on the stack */ +static int +slapi_over_merge_controls( Operation *op, SlapReply *rs ) +{ + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + LDAPControl **ctrls = NULL; + LDAPControl **slapi_ctrls = NULL; + size_t n_slapi_ctrls = 0; + size_t n_rs_ctrls = 0; + size_t i; + + slapi_pblock_get( pb, SLAPI_RESCONTROLS, (void **)&slapi_ctrls ); + + n_slapi_ctrls = slapi_int_count_controls( slapi_ctrls ); + n_rs_ctrls = slapi_int_count_controls( rs->sr_ctrls ); + + if ( n_slapi_ctrls == 0 ) + return LDAP_SUCCESS; /* no SLAPI controls */ + + slapi_pblock_set( pb, SLAPI_X_OLD_RESCONTROLS, (void *)rs->sr_ctrls ); + + ctrls = (LDAPControl **) op->o_tmpalloc( + ( n_slapi_ctrls + n_rs_ctrls + 1 ) * sizeof(LDAPControl *), + op->o_tmpmemctx ); + + for ( i = 0; i < n_slapi_ctrls; i++ ) { + ctrls[i] = slapi_ctrls[i]; + } + if ( rs->sr_ctrls != NULL ) { + for ( i = 0; i < n_rs_ctrls; i++ ) { + ctrls[n_slapi_ctrls + i] = rs->sr_ctrls[i]; + } + } + ctrls[n_slapi_ctrls + n_rs_ctrls] = NULL; + + rs->sr_ctrls = ctrls; + + return LDAP_SUCCESS; +} + +static int +slapi_over_unmerge_controls( Operation *op, SlapReply *rs ) +{ + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + LDAPControl **rs_ctrls = NULL; + + slapi_pblock_get( pb, SLAPI_X_OLD_RESCONTROLS, (void **)&rs_ctrls ); + + if ( rs_ctrls == NULL || rs->sr_ctrls == rs_ctrls ) { + /* no copying done */ + return LDAP_SUCCESS; + } + + op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx ); + rs->sr_ctrls = rs_ctrls; + + return LDAP_SUCCESS; +} + +static int +slapi_over_response( Operation *op, SlapReply *rs ) +{ + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + int rc = SLAP_CB_CONTINUE; + + if ( pb->pb_intop == 0 ) { + switch ( rs->sr_type ) { + case REP_RESULT: + case REP_SASL: + case REP_EXTENDED: + rc = slapi_over_result( op, rs, SLAPI_PLUGIN_PRE_RESULT_FN ); + break; + case REP_SEARCH: + rc = slapi_over_search( op, rs, SLAPI_PLUGIN_PRE_ENTRY_FN ); + break; + case REP_SEARCHREF: + rc = slapi_over_search( op, rs, SLAPI_PLUGIN_PRE_REFERRAL_FN ); + break; + default: + break; + } + } + + slapi_over_merge_controls( op, rs ); + + return rc; +} + +static int +slapi_over_cleanup( Operation *op, SlapReply *rs ) +{ + Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); + int rc = SLAP_CB_CONTINUE; + + slapi_over_unmerge_controls( op, rs ); + + if ( pb->pb_intop == 0 ) { + switch ( rs->sr_type ) { + case REP_RESULT: + case REP_SASL: + case REP_EXTENDED: + rc = slapi_over_result( op, rs, SLAPI_PLUGIN_POST_RESULT_FN ); + break; + case REP_SEARCH: + rc = slapi_over_search( op, rs, SLAPI_PLUGIN_POST_ENTRY_FN ); + break; + case REP_SEARCHREF: + rc = slapi_over_search( op, rs, SLAPI_PLUGIN_POST_REFERRAL_FN ); + break; + default: + break; + } + } + + return rc; +} + +static int +slapi_op_func( Operation *op, SlapReply *rs ) +{ + Slapi_PBlock *pb; + slap_operation_t which; + struct slapi_op_info *opinfo; + int rc; + slap_overinfo *oi; + slap_overinst *on; + slap_callback cb; + int internal_op; + int preop_type, postop_type; + BackendDB *be; + + if ( !slapi_plugins_used ) + return SLAP_CB_CONTINUE; + + /* + * Find the SLAPI operation information for this LDAP + * operation; this will contain the preop and postop + * plugin types, as well as optional callbacks for + * setting up the SLAPI environment. + */ + which = slapi_tag2op( op->o_tag ); + if ( which >= op_last ) { + /* invalid operation, but let someone else deal with it */ + return SLAP_CB_CONTINUE; + } + + opinfo = &slapi_op_dispatch_table[which]; + if ( opinfo == NULL ) { + /* no SLAPI plugin types for this operation */ + return SLAP_CB_CONTINUE; + } + + internal_op = slapi_op_internal_p( op, rs, &cb ); + + if ( internal_op ) { + preop_type = opinfo->soi_internal_preop; + postop_type = opinfo->soi_internal_postop; + } else { + preop_type = opinfo->soi_preop; + postop_type = opinfo->soi_postop; + } + + if ( preop_type == 0 ) { + /* no SLAPI plugin types for this operation */ + pb = NULL; + rc = SLAP_CB_CONTINUE; + goto cleanup; + } + + pb = SLAPI_OPERATION_PBLOCK( op ); + + /* cache backend so we call correct postop plugins */ + be = pb->pb_op->o_bd; + + rc = slapi_int_call_plugins( be, preop_type, pb ); + + /* + * soi_callback is responsible for examining the result code + * of the preoperation plugin and determining whether to + * abort. This is needed because of special SLAPI behaviour + e with bind preoperation plugins. + * + * The soi_callback function is also used to reset any values + * returned from the preoperation plugin before calling the + * backend (for the success case). + */ + if ( opinfo->soi_callback == NULL ) { + /* default behaviour is preop plugin can abort operation */ + if ( rc < 0 ) { + rc = rs->sr_err; + goto cleanup; + } + } else { + rc = (opinfo->soi_callback)( op, rs, rc ); + if ( rc ) + goto cleanup; + } + + /* + * Call actual backend (or next overlay in stack). We need to + * do this rather than returning SLAP_CB_CONTINUE and calling + * postoperation plugins in a response handler to match the + * behaviour of SLAPI in OpenLDAP 2.2, where postoperation + * plugins are called after the backend has completely + * finished processing the operation. + */ + on = (slap_overinst *)op->o_bd->bd_info; + oi = on->on_info; + + rc = overlay_op_walk( op, rs, which, oi, on->on_next ); + + /* + * Call postoperation plugins + */ + slapi_int_call_plugins( be, postop_type, pb ); + +cleanup: + if ( !internal_op ) { + slapi_pblock_destroy(pb); + cb.sc_private = NULL; + } + + op->o_callback = cb.sc_next; + + return rc; +} + +static int +slapi_over_extended( Operation *op, SlapReply *rs ) +{ + Slapi_PBlock *pb; + SLAPI_FUNC callback; + int rc; + int internal_op; + slap_callback cb; + + slapi_int_get_extop_plugin( &op->ore_reqoid, &callback ); + if ( callback == NULL ) { + return SLAP_CB_CONTINUE; + } + + internal_op = slapi_op_internal_p( op, rs, &cb ); + if ( internal_op ) { + return SLAP_CB_CONTINUE; + } + + pb = SLAPI_OPERATION_PBLOCK( op ); + + rc = (*callback)( pb ); + if ( rc == SLAPI_PLUGIN_EXTENDED_SENT_RESULT ) { + goto cleanup; + } else if ( rc == SLAPI_PLUGIN_EXTENDED_NOT_HANDLED ) { + rc = SLAP_CB_CONTINUE; + goto cleanup; + } + + assert( rs->sr_rspoid != NULL ); + + send_ldap_extended( op, rs ); + +#if 0 + slapi_ch_free_string( (char **)&rs->sr_rspoid ); +#endif + + if ( rs->sr_rspdata != NULL ) + ber_bvfree( rs->sr_rspdata ); + + rc = rs->sr_err; + +cleanup: + slapi_pblock_destroy( pb ); + op->o_callback = cb.sc_next; + + return rc; +} + +static int +slapi_over_access_allowed( + Operation *op, + Entry *e, + AttributeDescription *desc, + struct berval *val, + slap_access_t access, + AccessControlState *state, + slap_mask_t *maskp ) +{ + int rc; + Slapi_PBlock *pb; + slap_callback cb; + int internal_op; + SlapReply rs = { REP_RESULT }; + + internal_op = slapi_op_internal_p( op, &rs, &cb ); + + cb.sc_response = NULL; + cb.sc_cleanup = NULL; + cb.sc_writewait = NULL; + + pb = SLAPI_OPERATION_PBLOCK( op ); + + rc = slapi_int_access_allowed( op, e, desc, val, access, state ); + if ( rc ) { + rc = SLAP_CB_CONTINUE; + } + + if ( !internal_op ) { + slapi_pblock_destroy( pb ); + } + + op->o_callback = cb.sc_next; + + return rc; +} + +static int +slapi_over_acl_group( + Operation *op, + Entry *target, + struct berval *gr_ndn, + struct berval *op_ndn, + ObjectClass *group_oc, + AttributeDescription *group_at ) +{ + Slapi_Entry *e; + int rc; + Slapi_PBlock *pb; + BackendDB *be = op->o_bd; + GroupAssertion *g; + SlapReply rs = { REP_RESULT }; + + op->o_bd = select_backend( gr_ndn, 0 ); + + for ( g = op->o_groups; g; g = g->ga_next ) { + if ( g->ga_be != op->o_bd || g->ga_oc != group_oc || + g->ga_at != group_at || g->ga_len != gr_ndn->bv_len ) + { + continue; + } + if ( strcmp( g->ga_ndn, gr_ndn->bv_val ) == 0 ) { + break; + } + } + if ( g != NULL ) { + rc = g->ga_res; + goto done; + } + + if ( target != NULL && dn_match( &target->e_nname, gr_ndn ) ) { + e = target; + rc = 0; + } else { + rc = be_entry_get_rw( op, gr_ndn, group_oc, group_at, 0, &e ); + } + if ( e != NULL ) { + int internal_op; + slap_callback cb; + + internal_op = slapi_op_internal_p( op, &rs, &cb ); + + cb.sc_response = NULL; + cb.sc_cleanup = NULL; + cb.sc_writewait = NULL; + + pb = SLAPI_OPERATION_PBLOCK( op ); + + slapi_pblock_set( pb, SLAPI_X_GROUP_ENTRY, (void *)e ); + slapi_pblock_set( pb, SLAPI_X_GROUP_OPERATION_DN, (void *)op_ndn->bv_val ); + slapi_pblock_set( pb, SLAPI_X_GROUP_ATTRIBUTE, (void *)group_at->ad_cname.bv_val ); + slapi_pblock_set( pb, SLAPI_X_GROUP_TARGET_ENTRY, (void *)target ); + + rc = slapi_over_call_plugins( pb, SLAPI_X_PLUGIN_PRE_GROUP_FN ); + if ( rc >= 0 ) /* 1 means no plugins called */ + rc = SLAP_CB_CONTINUE; + else + rc = pb->pb_rs->sr_err; + + slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ENTRY ); + slapi_pblock_delete_param( pb, SLAPI_X_GROUP_OPERATION_DN ); + slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ATTRIBUTE ); + slapi_pblock_delete_param( pb, SLAPI_X_GROUP_TARGET_ENTRY ); + + if ( !internal_op ) + slapi_pblock_destroy( pb ); + + if ( e != target ) { + be_entry_release_r( op, e ); + } + + op->o_callback = cb.sc_next; + } else { + rc = LDAP_NO_SUCH_OBJECT; /* return SLAP_CB_CONTINUE for correctness? */ + } + + if ( op->o_tag != LDAP_REQ_BIND && !op->o_do_not_cache && + rc != SLAP_CB_CONTINUE ) { + g = op->o_tmpalloc( sizeof( GroupAssertion ) + gr_ndn->bv_len, + op->o_tmpmemctx ); + g->ga_be = op->o_bd; + g->ga_oc = group_oc; + g->ga_at = group_at; + g->ga_res = rc; + g->ga_len = gr_ndn->bv_len; + strcpy( g->ga_ndn, gr_ndn->bv_val ); + g->ga_next = op->o_groups; + op->o_groups = g; + } + /* + * XXX don't call POST_GROUP_FN, I have no idea what the point of + * that plugin function was anyway + */ +done: + op->o_bd = be; + return rc; +} + +static int +slapi_over_db_open( + BackendDB *be, + ConfigReply *cr ) +{ + Slapi_PBlock *pb; + int rc; + + pb = slapi_pblock_new(); + + rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_START_FN, pb ); + + slapi_pblock_destroy( pb ); + + return rc; +} + +static int +slapi_over_db_close( + BackendDB *be, + ConfigReply *cr ) +{ + Slapi_PBlock *pb; + int rc; + + pb = slapi_pblock_new(); + + rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_CLOSE_FN, pb ); + + slapi_pblock_destroy( pb ); + + return rc; +} + +static int +slapi_over_init() +{ + memset( &slapi, 0, sizeof(slapi) ); + + slapi.on_bi.bi_type = SLAPI_OVERLAY_NAME; + + slapi.on_bi.bi_op_bind = slapi_op_func; + slapi.on_bi.bi_op_unbind = slapi_op_func; + slapi.on_bi.bi_op_search = slapi_op_func; + slapi.on_bi.bi_op_compare = slapi_op_func; + slapi.on_bi.bi_op_modify = slapi_op_func; + slapi.on_bi.bi_op_modrdn = slapi_op_func; + slapi.on_bi.bi_op_add = slapi_op_func; + slapi.on_bi.bi_op_delete = slapi_op_func; + slapi.on_bi.bi_op_abandon = slapi_op_func; + slapi.on_bi.bi_op_cancel = slapi_op_func; + + slapi.on_bi.bi_db_open = slapi_over_db_open; + slapi.on_bi.bi_db_close = slapi_over_db_close; + + slapi.on_bi.bi_extended = slapi_over_extended; + slapi.on_bi.bi_access_allowed = slapi_over_access_allowed; + slapi.on_bi.bi_operational = slapi_over_aux_operational; + slapi.on_bi.bi_acl_group = slapi_over_acl_group; + + return overlay_register( &slapi ); +} + +int slapi_over_is_inst( BackendDB *be ) +{ + return overlay_is_inst( be, SLAPI_OVERLAY_NAME ); +} + +int slapi_over_config( BackendDB *be, ConfigReply *cr ) +{ + if ( slapi_over_initialized == 0 ) { + int rc; + + /* do global initializaiton */ + ldap_pvt_thread_mutex_init( &slapi_hn_mutex ); + ldap_pvt_thread_mutex_init( &slapi_time_mutex ); + ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ); + + if ( slapi_log_file == NULL ) + slapi_log_file = slapi_ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" ); + + rc = slapi_int_init_object_extensions(); + if ( rc != 0 ) + return rc; + + rc = slapi_over_init(); + if ( rc != 0 ) + return rc; + + slapi_over_initialized = 1; + } + + return overlay_config( be, SLAPI_OVERLAY_NAME, -1, NULL, cr ); +} + +#endif /* LDAP_SLAPI */ diff --git a/servers/slapd/slapi/slapi_pblock.c b/servers/slapd/slapi/slapi_pblock.c new file mode 100644 index 0000000..65b308a --- /dev/null +++ b/servers/slapd/slapi/slapi_pblock.c @@ -0,0 +1,1426 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2002-2021 The OpenLDAP Foundation. + * Portions Copyright 1997,2002-2003 IBM Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by IBM Corporation for use in + * IBM products and subsequently ported to OpenLDAP Software by + * Steve Omrani. Additional significant contributors include: + * Luke Howard + */ + +#include "portable.h" +#include <slap.h> +#include <slapi.h> + +#ifdef LDAP_SLAPI + +/* some parameters require a valid connection and operation */ +#define PBLOCK_LOCK_CONN( _pb ) do { \ + ldap_pvt_thread_mutex_lock( &(_pb)->pb_conn->c_mutex ); \ + } while (0) + +#define PBLOCK_UNLOCK_CONN( _pb ) do { \ + ldap_pvt_thread_mutex_unlock( &(_pb)->pb_conn->c_mutex ); \ + } while (0) + +/* some parameters are only settable for internal operations */ +#define PBLOCK_VALIDATE_IS_INTOP( _pb ) do { if ( (_pb)->pb_intop == 0 ) break; } while ( 0 ) + +static slapi_pblock_class_t +pblock_get_param_class( int param ) +{ + switch ( param ) { + case SLAPI_PLUGIN_TYPE: + case SLAPI_PLUGIN_ARGC: + case SLAPI_PLUGIN_OPRETURN: + case SLAPI_PLUGIN_INTOP_RESULT: + case SLAPI_CONFIG_LINENO: + case SLAPI_CONFIG_ARGC: + case SLAPI_BIND_METHOD: + case SLAPI_MODRDN_DELOLDRDN: + case SLAPI_SEARCH_SCOPE: + case SLAPI_SEARCH_DEREF: + case SLAPI_SEARCH_SIZELIMIT: + case SLAPI_SEARCH_TIMELIMIT: + case SLAPI_SEARCH_ATTRSONLY: + case SLAPI_NENTRIES: + case SLAPI_CHANGENUMBER: + case SLAPI_DBSIZE: + case SLAPI_REQUESTOR_ISROOT: + case SLAPI_BE_READONLY: + case SLAPI_BE_LASTMOD: + case SLAPI_DB2LDIF_PRINTKEY: + case SLAPI_LDIF2DB_REMOVEDUPVALS: + case SLAPI_MANAGEDSAIT: + case SLAPI_X_RELAX: + case SLAPI_X_OPERATION_NO_SCHEMA_CHECK: + case SLAPI_IS_REPLICATED_OPERATION: + case SLAPI_X_CONN_IS_UDP: + case SLAPI_X_CONN_SSF: + case SLAPI_RESULT_CODE: + case SLAPI_LOG_OPERATION: + case SLAPI_IS_INTERNAL_OPERATION: + return PBLOCK_CLASS_INTEGER; + break; + + case SLAPI_CONN_ID: + case SLAPI_OPERATION_ID: + case SLAPI_OPINITIATED_TIME: + case SLAPI_ABANDON_MSGID: + case SLAPI_X_OPERATION_DELETE_GLUE_PARENT: + case SLAPI_OPERATION_MSGID: + return PBLOCK_CLASS_LONG_INTEGER; + break; + + case SLAPI_PLUGIN_DESTROY_FN: + case SLAPI_PLUGIN_DB_BIND_FN: + case SLAPI_PLUGIN_DB_UNBIND_FN: + case SLAPI_PLUGIN_DB_SEARCH_FN: + case SLAPI_PLUGIN_DB_COMPARE_FN: + case SLAPI_PLUGIN_DB_MODIFY_FN: + case SLAPI_PLUGIN_DB_MODRDN_FN: + case SLAPI_PLUGIN_DB_ADD_FN: + case SLAPI_PLUGIN_DB_DELETE_FN: + case SLAPI_PLUGIN_DB_ABANDON_FN: + case SLAPI_PLUGIN_DB_CONFIG_FN: + case SLAPI_PLUGIN_CLOSE_FN: + case SLAPI_PLUGIN_DB_FLUSH_FN: + case SLAPI_PLUGIN_START_FN: + case SLAPI_PLUGIN_DB_SEQ_FN: + case SLAPI_PLUGIN_DB_ENTRY_FN: + case SLAPI_PLUGIN_DB_REFERRAL_FN: + case SLAPI_PLUGIN_DB_RESULT_FN: + case SLAPI_PLUGIN_DB_LDIF2DB_FN: + case SLAPI_PLUGIN_DB_DB2LDIF_FN: + case SLAPI_PLUGIN_DB_BEGIN_FN: + case SLAPI_PLUGIN_DB_COMMIT_FN: + case SLAPI_PLUGIN_DB_ABORT_FN: + case SLAPI_PLUGIN_DB_ARCHIVE2DB_FN: + case SLAPI_PLUGIN_DB_DB2ARCHIVE_FN: + case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN: + case SLAPI_PLUGIN_DB_FREE_RESULT_SET_FN: + case SLAPI_PLUGIN_DB_SIZE_FN: + case SLAPI_PLUGIN_DB_TEST_FN: + case SLAPI_PLUGIN_DB_NO_ACL: + case SLAPI_PLUGIN_EXT_OP_FN: + case SLAPI_PLUGIN_EXT_OP_OIDLIST: + case SLAPI_PLUGIN_PRE_BIND_FN: + case SLAPI_PLUGIN_PRE_UNBIND_FN: + case SLAPI_PLUGIN_PRE_SEARCH_FN: + case SLAPI_PLUGIN_PRE_COMPARE_FN: + case SLAPI_PLUGIN_PRE_MODIFY_FN: + case SLAPI_PLUGIN_PRE_MODRDN_FN: + case SLAPI_PLUGIN_PRE_ADD_FN: + case SLAPI_PLUGIN_PRE_DELETE_FN: + case SLAPI_PLUGIN_PRE_ABANDON_FN: + case SLAPI_PLUGIN_PRE_ENTRY_FN: + case SLAPI_PLUGIN_PRE_REFERRAL_FN: + case SLAPI_PLUGIN_PRE_RESULT_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN: + case SLAPI_PLUGIN_BE_PRE_ADD_FN: + case SLAPI_PLUGIN_BE_PRE_MODIFY_FN: + case SLAPI_PLUGIN_BE_PRE_MODRDN_FN: + case SLAPI_PLUGIN_BE_PRE_DELETE_FN: + case SLAPI_PLUGIN_POST_BIND_FN: + case SLAPI_PLUGIN_POST_UNBIND_FN: + case SLAPI_PLUGIN_POST_SEARCH_FN: + case SLAPI_PLUGIN_POST_COMPARE_FN: + case SLAPI_PLUGIN_POST_MODIFY_FN: + case SLAPI_PLUGIN_POST_MODRDN_FN: + case SLAPI_PLUGIN_POST_ADD_FN: + case SLAPI_PLUGIN_POST_DELETE_FN: + case SLAPI_PLUGIN_POST_ABANDON_FN: + case SLAPI_PLUGIN_POST_ENTRY_FN: + case SLAPI_PLUGIN_POST_REFERRAL_FN: + case SLAPI_PLUGIN_POST_RESULT_FN: + case SLAPI_PLUGIN_INTERNAL_POST_ADD_FN: + case SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN: + case SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN: + case SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN: + case SLAPI_PLUGIN_BE_POST_ADD_FN: + case SLAPI_PLUGIN_BE_POST_MODIFY_FN: + case SLAPI_PLUGIN_BE_POST_MODRDN_FN: + case SLAPI_PLUGIN_BE_POST_DELETE_FN: + case SLAPI_PLUGIN_MR_FILTER_CREATE_FN: + case SLAPI_PLUGIN_MR_INDEXER_CREATE_FN: + case SLAPI_PLUGIN_MR_FILTER_MATCH_FN: + case SLAPI_PLUGIN_MR_FILTER_INDEX_FN: + case SLAPI_PLUGIN_MR_FILTER_RESET_FN: + case SLAPI_PLUGIN_MR_INDEX_FN: + case SLAPI_PLUGIN_COMPUTE_EVALUATOR_FN: + case SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN: + case SLAPI_PLUGIN_ACL_ALLOW_ACCESS: + case SLAPI_X_PLUGIN_PRE_GROUP_FN: + case SLAPI_X_PLUGIN_POST_GROUP_FN: + case SLAPI_PLUGIN_AUDIT_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_UNBIND_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_SEARCH_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_COMPARE_FN: + case SLAPI_PLUGIN_INTERNAL_PRE_ABANDON_FN: + case SLAPI_PLUGIN_INTERNAL_POST_BIND_FN: + case SLAPI_PLUGIN_INTERNAL_POST_UNBIND_FN: + case SLAPI_PLUGIN_INTERNAL_POST_SEARCH_FN: + case SLAPI_PLUGIN_INTERNAL_POST_COMPARE_FN: + case SLAPI_PLUGIN_INTERNAL_POST_ABANDON_FN: + return PBLOCK_CLASS_FUNCTION_POINTER; + break; + + case SLAPI_BACKEND: + case SLAPI_CONNECTION: + case SLAPI_OPERATION: + case SLAPI_OPERATION_PARAMETERS: + case SLAPI_OPERATION_TYPE: + case SLAPI_OPERATION_AUTHTYPE: + case SLAPI_BE_MONITORDN: + case SLAPI_BE_TYPE: + case SLAPI_REQUESTOR_DN: + case SLAPI_CONN_DN: + case SLAPI_CONN_CLIENTIP: + case SLAPI_CONN_SERVERIP: + case SLAPI_CONN_AUTHTYPE: + case SLAPI_CONN_AUTHMETHOD: + case SLAPI_CONN_CERT: + case SLAPI_X_CONN_CLIENTPATH: + case SLAPI_X_CONN_SERVERPATH: + case SLAPI_X_CONN_SASL_CONTEXT: + case SLAPI_X_CONFIG_ARGV: + case SLAPI_X_INTOP_FLAGS: + case SLAPI_X_INTOP_RESULT_CALLBACK: + case SLAPI_X_INTOP_SEARCH_ENTRY_CALLBACK: + case SLAPI_X_INTOP_REFERRAL_ENTRY_CALLBACK: + case SLAPI_X_INTOP_CALLBACK_DATA: + case SLAPI_PLUGIN_MR_OID: + case SLAPI_PLUGIN_MR_TYPE: + case SLAPI_PLUGIN_MR_VALUE: + case SLAPI_PLUGIN_MR_VALUES: + case SLAPI_PLUGIN_MR_KEYS: + case SLAPI_PLUGIN: + case SLAPI_PLUGIN_PRIVATE: + case SLAPI_PLUGIN_ARGV: + case SLAPI_PLUGIN_OBJECT: + case SLAPI_PLUGIN_DESCRIPTION: + case SLAPI_PLUGIN_IDENTITY: + case SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES: + case SLAPI_PLUGIN_INTOP_SEARCH_REFERRALS: + case SLAPI_PLUGIN_MR_FILTER_REUSABLE: + case SLAPI_PLUGIN_MR_QUERY_OPERATOR: + case SLAPI_PLUGIN_MR_USAGE: + case SLAPI_OP_LESS: + case SLAPI_OP_LESS_OR_EQUAL: + case SLAPI_PLUGIN_MR_USAGE_INDEX: + case SLAPI_PLUGIN_SYNTAX_FILTER_AVA: + case SLAPI_PLUGIN_SYNTAX_FILTER_SUB: + case SLAPI_PLUGIN_SYNTAX_VALUES2KEYS: + case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA: + case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB: + case SLAPI_PLUGIN_SYNTAX_NAMES: + case SLAPI_PLUGIN_SYNTAX_OID: + case SLAPI_PLUGIN_SYNTAX_FLAGS: + case SLAPI_PLUGIN_SYNTAX_COMPARE: + case SLAPI_CONFIG_FILENAME: + case SLAPI_CONFIG_ARGV: + case SLAPI_TARGET_ADDRESS: + case SLAPI_TARGET_UNIQUEID: + case SLAPI_TARGET_DN: + case SLAPI_REQCONTROLS: + case SLAPI_ENTRY_PRE_OP: + case SLAPI_ENTRY_POST_OP: + case SLAPI_RESCONTROLS: + case SLAPI_X_OLD_RESCONTROLS: + case SLAPI_ADD_RESCONTROL: + case SLAPI_CONTROLS_ARG: + case SLAPI_ADD_ENTRY: + case SLAPI_ADD_EXISTING_DN_ENTRY: + case SLAPI_ADD_PARENT_ENTRY: + case SLAPI_ADD_PARENT_UNIQUEID: + case SLAPI_ADD_EXISTING_UNIQUEID_ENTRY: + case SLAPI_BIND_CREDENTIALS: + case SLAPI_BIND_SASLMECHANISM: + case SLAPI_BIND_RET_SASLCREDS: + case SLAPI_COMPARE_TYPE: + case SLAPI_COMPARE_VALUE: + case SLAPI_MODIFY_MODS: + case SLAPI_MODRDN_NEWRDN: + case SLAPI_MODRDN_NEWSUPERIOR: + case SLAPI_MODRDN_PARENT_ENTRY: + case SLAPI_MODRDN_NEWPARENT_ENTRY: + case SLAPI_MODRDN_TARGET_ENTRY: + case SLAPI_MODRDN_NEWSUPERIOR_ADDRESS: + case SLAPI_SEARCH_FILTER: + case SLAPI_SEARCH_STRFILTER: + case SLAPI_SEARCH_ATTRS: + case SLAPI_SEQ_TYPE: + case SLAPI_SEQ_ATTRNAME: + case SLAPI_SEQ_VAL: + case SLAPI_EXT_OP_REQ_OID: + case SLAPI_EXT_OP_REQ_VALUE: + case SLAPI_EXT_OP_RET_OID: + case SLAPI_EXT_OP_RET_VALUE: + case SLAPI_MR_FILTER_ENTRY: + case SLAPI_MR_FILTER_TYPE: + case SLAPI_MR_FILTER_VALUE: + case SLAPI_MR_FILTER_OID: + case SLAPI_MR_FILTER_DNATTRS: + case SLAPI_LDIF2DB_FILE: + case SLAPI_PARENT_TXN: + case SLAPI_TXN: + case SLAPI_SEARCH_RESULT_SET: + case SLAPI_SEARCH_RESULT_ENTRY: + case SLAPI_SEARCH_REFERRALS: + case SLAPI_RESULT_TEXT: + case SLAPI_RESULT_MATCHED: + case SLAPI_X_GROUP_ENTRY: + case SLAPI_X_GROUP_ATTRIBUTE: + case SLAPI_X_GROUP_OPERATION_DN: + case SLAPI_X_GROUP_TARGET_ENTRY: + case SLAPI_X_ADD_STRUCTURAL_CLASS: + case SLAPI_PLUGIN_AUDIT_DATA: + case SLAPI_IBM_PBLOCK: + case SLAPI_PLUGIN_VERSION: + return PBLOCK_CLASS_POINTER; + break; + default: + break; + } + + return PBLOCK_CLASS_INVALID; +} + +static void +pblock_lock( Slapi_PBlock *pb ) +{ + ldap_pvt_thread_mutex_lock( &pb->pb_mutex ); +} + +static void +pblock_unlock( Slapi_PBlock *pb ) +{ + ldap_pvt_thread_mutex_unlock( &pb->pb_mutex ); +} + +static int +pblock_get_default( Slapi_PBlock *pb, int param, void **value ) +{ + int i; + slapi_pblock_class_t pbClass; + + pbClass = pblock_get_param_class( param ); + if ( pbClass == PBLOCK_CLASS_INVALID ) { + return PBLOCK_ERROR; + } + + switch ( pbClass ) { + case PBLOCK_CLASS_INTEGER: + *((int *)value) = 0; + break; + case PBLOCK_CLASS_LONG_INTEGER: + *((long *)value) = 0L; + break; + case PBLOCK_CLASS_POINTER: + case PBLOCK_CLASS_FUNCTION_POINTER: + *value = NULL; + break; + case PBLOCK_CLASS_INVALID: + return PBLOCK_ERROR; + } + + for ( i = 0; i < pb->pb_nParams; i++ ) { + if ( pb->pb_params[i] == param ) { + switch ( pbClass ) { + case PBLOCK_CLASS_INTEGER: + *((int *)value) = pb->pb_values[i].pv_integer; + break; + case PBLOCK_CLASS_LONG_INTEGER: + *((long *)value) = pb->pb_values[i].pv_long_integer; + break; + case PBLOCK_CLASS_POINTER: + *value = pb->pb_values[i].pv_pointer; + break; + case PBLOCK_CLASS_FUNCTION_POINTER: + *value = pb->pb_values[i].pv_function_pointer; + break; + default: + break; + } + break; + } + } + + return PBLOCK_SUCCESS; +} + +static char * +pblock_get_authtype( AuthorizationInformation *authz, int is_tls ) +{ + char *authType; + + switch ( authz->sai_method ) { + case LDAP_AUTH_SASL: + authType = SLAPD_AUTH_SASL; + break; + case LDAP_AUTH_SIMPLE: + authType = SLAPD_AUTH_SIMPLE; + break; + case LDAP_AUTH_NONE: + authType = SLAPD_AUTH_NONE; + break; + default: + authType = NULL; + break; + } + + if ( is_tls && authType == NULL ) { + authType = SLAPD_AUTH_SSL; + } + + return authType; +} + +static int +pblock_set_default( Slapi_PBlock *pb, int param, void *value ) +{ + slapi_pblock_class_t pbClass; + int i; + + pbClass = pblock_get_param_class( param ); + if ( pbClass == PBLOCK_CLASS_INVALID ) { + return PBLOCK_ERROR; + } + + if ( pb->pb_nParams == PBLOCK_MAX_PARAMS ) { + return PBLOCK_ERROR; + } + + for ( i = 0; i < pb->pb_nParams; i++ ) { + if ( pb->pb_params[i] == param ) + break; + } + if ( i >= pb->pb_nParams ) { + pb->pb_params[i] = param; + pb->pb_nParams++; + } + + switch ( pbClass ) { + case PBLOCK_CLASS_INTEGER: + pb->pb_values[i].pv_integer = (*((int *)value)); + break; + case PBLOCK_CLASS_LONG_INTEGER: + pb->pb_values[i].pv_long_integer = (*((long *)value)); + break; + case PBLOCK_CLASS_POINTER: + pb->pb_values[i].pv_pointer = value; + break; + case PBLOCK_CLASS_FUNCTION_POINTER: + pb->pb_values[i].pv_function_pointer = value; + break; + default: + break; + } + + return PBLOCK_SUCCESS; +} + +static int +pblock_be_call( Slapi_PBlock *pb, int (*bep)(Operation *) ) +{ + BackendDB *be_orig; + Operation *op; + int rc; + + PBLOCK_ASSERT_OP( pb, 0 ); + op = pb->pb_op; + + be_orig = op->o_bd; + op->o_bd = select_backend( &op->o_req_ndn, 0 ); + rc = (*bep)( op ); + op->o_bd = be_orig; + + return rc; +} + +static int +pblock_get( Slapi_PBlock *pb, int param, void **value ) +{ + int rc = PBLOCK_SUCCESS; + + pblock_lock( pb ); + + switch ( param ) { + case SLAPI_OPERATION: + *value = pb->pb_op; + break; + case SLAPI_OPINITIATED_TIME: + PBLOCK_ASSERT_OP( pb, 0 ); + *((long *)value) = pb->pb_op->o_time; + break; + case SLAPI_OPERATION_ID: + PBLOCK_ASSERT_OP( pb, 0 ); + *((long *)value) = pb->pb_op->o_opid; + break; + case SLAPI_OPERATION_TYPE: + PBLOCK_ASSERT_OP( pb, 0 ); + *((ber_tag_t *)value) = pb->pb_op->o_tag; + break; + case SLAPI_OPERATION_MSGID: + PBLOCK_ASSERT_OP( pb, 0 ); + *((long *)value) = pb->pb_op->o_msgid; + break; + case SLAPI_X_OPERATION_DELETE_GLUE_PARENT: + PBLOCK_ASSERT_OP( pb, 0 ); + *((int *)value) = pb->pb_op->o_delete_glue_parent; + break; + case SLAPI_X_OPERATION_NO_SCHEMA_CHECK: + PBLOCK_ASSERT_OP( pb, 0 ); + *((int *)value) = get_no_schema_check( pb->pb_op ); + break; + case SLAPI_X_ADD_STRUCTURAL_CLASS: + PBLOCK_ASSERT_OP( pb, 0 ); + + if ( pb->pb_op->o_tag == LDAP_REQ_ADD ) { + struct berval tmpval = BER_BVNULL; + + rc = mods_structural_class( pb->pb_op->ora_modlist, + &tmpval, &pb->pb_rs->sr_text, + pb->pb_textbuf, sizeof( pb->pb_textbuf ), + pb->pb_op->o_tmpmemctx ); + *((char **)value) = tmpval.bv_val; + } else { + rc = PBLOCK_ERROR; + } + break; + case SLAPI_X_OPERATION_NO_SUBORDINATE_GLUE: + PBLOCK_ASSERT_OP( pb, 0 ); + *((int *)value) = pb->pb_op->o_no_subordinate_glue; + break; + case SLAPI_REQCONTROLS: + PBLOCK_ASSERT_OP( pb, 0 ); + *((LDAPControl ***)value) = pb->pb_op->o_ctrls; + break; + case SLAPI_REQUESTOR_DN: + PBLOCK_ASSERT_OP( pb, 0 ); + *((char **)value) = pb->pb_op->o_dn.bv_val; + break; + case SLAPI_MANAGEDSAIT: + PBLOCK_ASSERT_OP( pb, 0 ); + *((int *)value) = get_manageDSAit( pb->pb_op ); + break; + case SLAPI_X_RELAX: + PBLOCK_ASSERT_OP( pb, 0 ); + *((int *)value) = get_relax( pb->pb_op ); + break; + case SLAPI_BACKEND: + PBLOCK_ASSERT_OP( pb, 0 ); + *((BackendDB **)value) = select_backend( &pb->pb_op->o_req_ndn, 0 ); + break; + case SLAPI_BE_TYPE: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_bd != NULL ) + *((char **)value) = pb->pb_op->o_bd->bd_info->bi_type; + else + *value = NULL; + break; + case SLAPI_CONNECTION: + *value = pb->pb_conn; + break; + case SLAPI_X_CONN_SSF: + PBLOCK_ASSERT_OP( pb, 0 ); + *((slap_ssf_t *)value) = pb->pb_conn->c_ssf; + break; + case SLAPI_X_CONN_SASL_CONTEXT: + PBLOCK_ASSERT_CONN( pb ); + if ( pb->pb_conn->c_sasl_authctx != NULL ) + *value = pb->pb_conn->c_sasl_authctx; + else + *value = pb->pb_conn->c_sasl_sockctx; + break; + case SLAPI_TARGET_DN: + PBLOCK_ASSERT_OP( pb, 0 ); + *((char **)value) = pb->pb_op->o_req_dn.bv_val; + break; + case SLAPI_REQUESTOR_ISROOT: + *((int *)value) = pblock_be_call( pb, be_isroot ); + break; + case SLAPI_IS_REPLICATED_OPERATION: + *((int *)value) = pblock_be_call( pb, be_slurp_update ); + break; + case SLAPI_CONN_AUTHTYPE: + case SLAPI_CONN_AUTHMETHOD: /* XXX should return SASL mech */ + PBLOCK_ASSERT_CONN( pb ); + *((char **)value) = pblock_get_authtype( &pb->pb_conn->c_authz, +#ifdef HAVE_TLS + pb->pb_conn->c_is_tls +#else + 0 +#endif + ); + break; + case SLAPI_IS_INTERNAL_OPERATION: + *((int *)value) = pb->pb_intop; + break; + case SLAPI_X_CONN_IS_UDP: + PBLOCK_ASSERT_CONN( pb ); +#ifdef LDAP_CONNECTIONLESS + *((int *)value) = pb->pb_conn->c_is_udp; +#else + *((int *)value) = 0; +#endif + break; + case SLAPI_CONN_ID: + PBLOCK_ASSERT_CONN( pb ); + *((long *)value) = pb->pb_conn->c_connid; + break; + case SLAPI_CONN_DN: + PBLOCK_ASSERT_CONN( pb ); +#if 0 + /* This would be necessary to keep plugin compat after the fix in ITS#4158 */ + if ( pb->pb_op->o_tag == LDAP_REQ_BIND && pb->pb_rs->sr_err == LDAP_SUCCESS ) + *((char **)value) = pb->pb_op->orb_edn.bv_val; + else +#endif + *((char **)value) = pb->pb_conn->c_dn.bv_val; + break; + case SLAPI_CONN_CLIENTIP: + PBLOCK_ASSERT_CONN( pb ); + if ( strncmp( pb->pb_conn->c_peer_name.bv_val, "IP=", 3 ) == 0 ) + *((char **)value) = &pb->pb_conn->c_peer_name.bv_val[3]; + else + *value = NULL; + break; + case SLAPI_X_CONN_CLIENTPATH: + PBLOCK_ASSERT_CONN( pb ); + if ( strncmp( pb->pb_conn->c_peer_name.bv_val, "PATH=", 3 ) == 0 ) + *((char **)value) = &pb->pb_conn->c_peer_name.bv_val[5]; + else + *value = NULL; + break; + case SLAPI_CONN_SERVERIP: + PBLOCK_ASSERT_CONN( pb ); + if ( strncmp( pb->pb_conn->c_sock_name.bv_val, "IP=", 3 ) == 0 ) + *((char **)value) = &pb->pb_conn->c_sock_name.bv_val[3]; + else + *value = NULL; + break; + case SLAPI_X_CONN_SERVERPATH: + PBLOCK_ASSERT_CONN( pb ); + if ( strncmp( pb->pb_conn->c_sock_name.bv_val, "PATH=", 3 ) == 0 ) + *((char **)value) = &pb->pb_conn->c_sock_name.bv_val[5]; + else + *value = NULL; + break; + case SLAPI_RESULT_CODE: + case SLAPI_PLUGIN_INTOP_RESULT: + PBLOCK_ASSERT_OP( pb, 0 ); + *((int *)value) = pb->pb_rs->sr_err; + break; + case SLAPI_RESULT_TEXT: + PBLOCK_ASSERT_OP( pb, 0 ); + *((const char **)value) = pb->pb_rs->sr_text; + break; + case SLAPI_RESULT_MATCHED: + PBLOCK_ASSERT_OP( pb, 0 ); + *((const char **)value) = pb->pb_rs->sr_matched; + break; + case SLAPI_ADD_ENTRY: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_ADD ) + *((Slapi_Entry **)value) = pb->pb_op->ora_e; + else + *value = NULL; + break; + case SLAPI_MODIFY_MODS: { + LDAPMod **mods = NULL; + Modifications *ml = NULL; + + pblock_get_default( pb, param, (void **)&mods ); + if ( mods == NULL && pb->pb_intop == 0 ) { + switch ( pb->pb_op->o_tag ) { + case LDAP_REQ_MODIFY: + ml = pb->pb_op->orm_modlist; + break; + case LDAP_REQ_MODRDN: + ml = pb->pb_op->orr_modlist; + break; + default: + rc = PBLOCK_ERROR; + break; + } + if ( rc != PBLOCK_ERROR ) { + mods = slapi_int_modifications2ldapmods( ml ); + pblock_set_default( pb, param, (void *)mods ); + } + } + *((LDAPMod ***)value) = mods; + break; + } + case SLAPI_MODRDN_NEWRDN: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) + *((char **)value) = pb->pb_op->orr_newrdn.bv_val; + else + *value = NULL; + break; + case SLAPI_MODRDN_NEWSUPERIOR: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN && pb->pb_op->orr_newSup != NULL ) + *((char **)value) = pb->pb_op->orr_newSup->bv_val; + else + *value = NULL; + break; + case SLAPI_MODRDN_DELOLDRDN: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) + *((int *)value) = pb->pb_op->orr_deleteoldrdn; + else + *((int *)value) = 0; + break; + case SLAPI_SEARCH_SCOPE: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + *((int *)value) = pb->pb_op->ors_scope; + else + *((int *)value) = 0; + break; + case SLAPI_SEARCH_DEREF: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + *((int *)value) = pb->pb_op->ors_deref; + else + *((int *)value) = 0; + break; + case SLAPI_SEARCH_SIZELIMIT: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + *((int *)value) = pb->pb_op->ors_slimit; + else + *((int *)value) = 0; + break; + case SLAPI_SEARCH_TIMELIMIT: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + *((int *)value) = pb->pb_op->ors_tlimit; + else + *((int *)value) = 0; + break; + case SLAPI_SEARCH_FILTER: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + *((Slapi_Filter **)value) = pb->pb_op->ors_filter; + else + *((Slapi_Filter **)value) = NULL; + break; + case SLAPI_SEARCH_STRFILTER: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + *((char **)value) = pb->pb_op->ors_filterstr.bv_val; + else + *((char **)value) = NULL; + break; + case SLAPI_SEARCH_ATTRS: { + char **attrs = NULL; + + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag != LDAP_REQ_SEARCH ) { + rc = PBLOCK_ERROR; + break; + } + pblock_get_default( pb, param, (void **)&attrs ); + if ( attrs == NULL && pb->pb_intop == 0 ) { + attrs = anlist2charray_x( pb->pb_op->ors_attrs, 0, pb->pb_op->o_tmpmemctx ); + pblock_set_default( pb, param, (void *)attrs ); + } + *((char ***)value) = attrs; + break; + } + case SLAPI_SEARCH_ATTRSONLY: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + *((int *)value) = pb->pb_op->ors_attrsonly; + else + *((int *)value) = 0; + break; + case SLAPI_SEARCH_RESULT_ENTRY: + PBLOCK_ASSERT_OP( pb, 0 ); + *((Slapi_Entry **)value) = pb->pb_rs->sr_entry; + break; + case SLAPI_BIND_RET_SASLCREDS: + PBLOCK_ASSERT_OP( pb, 0 ); + *((struct berval **)value) = pb->pb_rs->sr_sasldata; + break; + case SLAPI_EXT_OP_REQ_OID: + *((const char **)value) = pb->pb_op->ore_reqoid.bv_val; + break; + case SLAPI_EXT_OP_REQ_VALUE: + *((struct berval **)value) = pb->pb_op->ore_reqdata; + break; + case SLAPI_EXT_OP_RET_OID: + PBLOCK_ASSERT_OP( pb, 0 ); + *((const char **)value) = pb->pb_rs->sr_rspoid; + break; + case SLAPI_EXT_OP_RET_VALUE: + PBLOCK_ASSERT_OP( pb, 0 ); + *((struct berval **)value) = pb->pb_rs->sr_rspdata; + break; + case SLAPI_BIND_METHOD: + if ( pb->pb_op->o_tag == LDAP_REQ_BIND ) + *((int *)value) = pb->pb_op->orb_method; + else + *((int *)value) = 0; + break; + case SLAPI_BIND_CREDENTIALS: + if ( pb->pb_op->o_tag == LDAP_REQ_BIND ) + *((struct berval **)value) = &pb->pb_op->orb_cred; + else + *value = NULL; + break; + case SLAPI_COMPARE_TYPE: + if ( pb->pb_op->o_tag == LDAP_REQ_COMPARE ) + *((char **)value) = pb->pb_op->orc_ava->aa_desc->ad_cname.bv_val; + else + *value = NULL; + break; + case SLAPI_COMPARE_VALUE: + if ( pb->pb_op->o_tag == LDAP_REQ_COMPARE ) + *((struct berval **)value) = &pb->pb_op->orc_ava->aa_value; + else + *value = NULL; + break; + case SLAPI_ABANDON_MSGID: + if ( pb->pb_op->o_tag == LDAP_REQ_ABANDON ) + *((int *)value) = pb->pb_op->orn_msgid; + else + *((int *)value) = 0; + break; + default: + rc = pblock_get_default( pb, param, value ); + break; + } + + pblock_unlock( pb ); + + return rc; +} + +static int +pblock_add_control( Slapi_PBlock *pb, LDAPControl *control ) +{ + LDAPControl **controls = NULL; + size_t i; + + pblock_get_default( pb, SLAPI_RESCONTROLS, (void **)&controls ); + + if ( controls != NULL ) { + for ( i = 0; controls[i] != NULL; i++ ) + ; + } else { + i = 0; + } + + controls = (LDAPControl **)slapi_ch_realloc( (char *)controls, + ( i + 2 ) * sizeof(LDAPControl *)); + controls[i++] = slapi_dup_control( control ); + controls[i] = NULL; + + return pblock_set_default( pb, SLAPI_RESCONTROLS, (void *)controls ); +} + +static int +pblock_set_dn( void *value, struct berval *dn, struct berval *ndn, void *memctx ) +{ + struct berval bv; + + if ( !BER_BVISNULL( dn )) { + slap_sl_free( dn->bv_val, memctx ); + BER_BVZERO( dn ); + } + if ( !BER_BVISNULL( ndn )) { + slap_sl_free( ndn->bv_val, memctx ); + BER_BVZERO( ndn ); + } + + bv.bv_val = (char *)value; + bv.bv_len = ( value != NULL ) ? strlen( bv.bv_val ) : 0; + + return dnPrettyNormal( NULL, &bv, dn, ndn, memctx ); +} + +static int +pblock_set( Slapi_PBlock *pb, int param, void *value ) +{ + int rc = PBLOCK_SUCCESS; + + pblock_lock( pb ); + + switch ( param ) { + case SLAPI_OPERATION: + pb->pb_op = (Operation *)value; + break; + case SLAPI_OPINITIATED_TIME: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_time = *((long *)value); + break; + case SLAPI_OPERATION_ID: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_opid = *((long *)value); + break; + case SLAPI_OPERATION_TYPE: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_tag = *((ber_tag_t *)value); + break; + case SLAPI_OPERATION_MSGID: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_msgid = *((long *)value); + break; + case SLAPI_X_OPERATION_DELETE_GLUE_PARENT: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_delete_glue_parent = *((int *)value); + break; + case SLAPI_X_OPERATION_NO_SCHEMA_CHECK: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_no_schema_check = *((int *)value); + break; + case SLAPI_X_OPERATION_NO_SUBORDINATE_GLUE: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_no_subordinate_glue = *((int *)value); + break; + case SLAPI_REQCONTROLS: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_ctrls = (LDAPControl **)value; + break; + case SLAPI_RESCONTROLS: { + LDAPControl **ctrls = NULL; + + pblock_get_default( pb, param, (void **)&ctrls ); + if ( ctrls != NULL ) { + /* free old ones first */ + ldap_controls_free( ctrls ); + } + rc = pblock_set_default( pb, param, value ); + break; + } + case SLAPI_ADD_RESCONTROL: + PBLOCK_ASSERT_OP( pb, 0 ); + rc = pblock_add_control( pb, (LDAPControl *)value ); + break; + case SLAPI_REQUESTOR_DN: + PBLOCK_ASSERT_OP( pb, 0 ); + rc = pblock_set_dn( value, &pb->pb_op->o_dn, &pb->pb_op->o_ndn, pb->pb_op->o_tmpmemctx ); + break; + case SLAPI_MANAGEDSAIT: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_managedsait = *((int *)value); + break; + case SLAPI_X_RELAX: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_relax = *((int *)value); + break; + case SLAPI_BACKEND: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_op->o_bd = (BackendDB *)value; + break; + case SLAPI_CONNECTION: + pb->pb_conn = (Connection *)value; + break; + case SLAPI_X_CONN_SSF: + PBLOCK_ASSERT_CONN( pb ); + PBLOCK_LOCK_CONN( pb ); + pb->pb_conn->c_ssf = (slap_ssf_t)(long)value; + PBLOCK_UNLOCK_CONN( pb ); + break; + case SLAPI_X_CONN_SASL_CONTEXT: + PBLOCK_ASSERT_CONN( pb ); + PBLOCK_LOCK_CONN( pb ); + pb->pb_conn->c_sasl_authctx = value; + PBLOCK_UNLOCK_CONN( pb ); + break; + case SLAPI_TARGET_DN: + PBLOCK_ASSERT_OP( pb, 0 ); + rc = pblock_set_dn( value, &pb->pb_op->o_req_dn, &pb->pb_op->o_req_ndn, pb->pb_op->o_tmpmemctx ); + break; + case SLAPI_CONN_ID: + PBLOCK_ASSERT_CONN( pb ); + PBLOCK_LOCK_CONN( pb ); + pb->pb_conn->c_connid = *((long *)value); + PBLOCK_UNLOCK_CONN( pb ); + break; + case SLAPI_CONN_DN: + PBLOCK_ASSERT_CONN( pb ); + PBLOCK_LOCK_CONN( pb ); + rc = pblock_set_dn( value, &pb->pb_conn->c_dn, &pb->pb_conn->c_ndn, NULL ); + PBLOCK_UNLOCK_CONN( pb ); + break; + case SLAPI_RESULT_CODE: + case SLAPI_PLUGIN_INTOP_RESULT: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_rs->sr_err = *((int *)value); + break; + case SLAPI_RESULT_TEXT: + PBLOCK_ASSERT_OP( pb, 0 ); + snprintf( pb->pb_textbuf, sizeof( pb->pb_textbuf ), "%s", (char *)value ); + pb->pb_rs->sr_text = pb->pb_textbuf; + break; + case SLAPI_RESULT_MATCHED: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_rs->sr_matched = (char *)value; /* XXX should dup? */ + break; + case SLAPI_ADD_ENTRY: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_ADD ) + pb->pb_op->ora_e = (Slapi_Entry *)value; + else + rc = PBLOCK_ERROR; + break; + case SLAPI_MODIFY_MODS: { + Modifications **mlp; + Modifications *newmods; + + PBLOCK_ASSERT_OP( pb, 0 ); + rc = pblock_set_default( pb, param, value ); + if ( rc != PBLOCK_SUCCESS ) { + break; + } + + if ( pb->pb_op->o_tag == LDAP_REQ_MODIFY ) { + mlp = &pb->pb_op->orm_modlist; + } else if ( pb->pb_op->o_tag == LDAP_REQ_ADD ) { + mlp = &pb->pb_op->ora_modlist; + } else if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) { + mlp = &pb->pb_op->orr_modlist; + } else { + break; + } + + newmods = slapi_int_ldapmods2modifications( pb->pb_op, (LDAPMod **)value ); + if ( newmods != NULL ) { + slap_mods_free( *mlp, 1 ); + *mlp = newmods; + } + break; + } + case SLAPI_MODRDN_NEWRDN: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) { + rc = pblock_set_dn( value, &pb->pb_op->orr_newrdn, &pb->pb_op->orr_nnewrdn, pb->pb_op->o_tmpmemctx ); + if ( rc == LDAP_SUCCESS ) + rc = rdn_validate( &pb->pb_op->orr_nnewrdn ); + } else { + rc = PBLOCK_ERROR; + } + break; + case SLAPI_MODRDN_NEWSUPERIOR: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) { + if ( value == NULL ) { + if ( pb->pb_op->orr_newSup != NULL ) { + pb->pb_op->o_tmpfree( pb->pb_op->orr_newSup, pb->pb_op->o_tmpmemctx ); + BER_BVZERO( pb->pb_op->orr_newSup ); + pb->pb_op->orr_newSup = NULL; + } + if ( pb->pb_op->orr_newSup != NULL ) { + pb->pb_op->o_tmpfree( pb->pb_op->orr_nnewSup, pb->pb_op->o_tmpmemctx ); + BER_BVZERO( pb->pb_op->orr_nnewSup ); + pb->pb_op->orr_nnewSup = NULL; + } + } else { + if ( pb->pb_op->orr_newSup == NULL ) { + pb->pb_op->orr_newSup = (struct berval *)pb->pb_op->o_tmpalloc( + sizeof(struct berval), pb->pb_op->o_tmpmemctx ); + BER_BVZERO( pb->pb_op->orr_newSup ); + } + if ( pb->pb_op->orr_nnewSup == NULL ) { + pb->pb_op->orr_nnewSup = (struct berval *)pb->pb_op->o_tmpalloc( + sizeof(struct berval), pb->pb_op->o_tmpmemctx ); + BER_BVZERO( pb->pb_op->orr_nnewSup ); + } + rc = pblock_set_dn( value, pb->pb_op->orr_newSup, pb->pb_op->orr_nnewSup, pb->pb_op->o_tmpmemctx ); + } + } else { + rc = PBLOCK_ERROR; + } + break; + case SLAPI_MODRDN_DELOLDRDN: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) + pb->pb_op->orr_deleteoldrdn = *((int *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_SEARCH_SCOPE: { + int scope = *((int *)value); + + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) { + switch ( *((int *)value) ) { + case LDAP_SCOPE_BASE: + case LDAP_SCOPE_ONELEVEL: + case LDAP_SCOPE_SUBTREE: + case LDAP_SCOPE_SUBORDINATE: + pb->pb_op->ors_scope = scope; + break; + default: + rc = PBLOCK_ERROR; + break; + } + } else { + rc = PBLOCK_ERROR; + } + break; + } + case SLAPI_SEARCH_DEREF: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + pb->pb_op->ors_deref = *((int *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_SEARCH_SIZELIMIT: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + pb->pb_op->ors_slimit = *((int *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_SEARCH_TIMELIMIT: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + pb->pb_op->ors_tlimit = *((int *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_SEARCH_FILTER: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + pb->pb_op->ors_filter = (Slapi_Filter *)value; + else + rc = PBLOCK_ERROR; + break; + case SLAPI_SEARCH_STRFILTER: + PBLOCK_ASSERT_OP( pb, 0 ); + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) { + pb->pb_op->ors_filterstr.bv_val = (char *)value; + pb->pb_op->ors_filterstr.bv_len = strlen((char *)value); + } else { + rc = PBLOCK_ERROR; + } + break; + case SLAPI_SEARCH_ATTRS: { + AttributeName *an = NULL; + size_t i = 0, j = 0; + char **attrs = (char **)value; + + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag != LDAP_REQ_SEARCH ) { + rc = PBLOCK_ERROR; + break; + } + /* also set mapped attrs */ + rc = pblock_set_default( pb, param, value ); + if ( rc != PBLOCK_SUCCESS ) { + break; + } + if ( pb->pb_op->ors_attrs != NULL ) { + pb->pb_op->o_tmpfree( pb->pb_op->ors_attrs, pb->pb_op->o_tmpmemctx ); + pb->pb_op->ors_attrs = NULL; + } + if ( attrs != NULL ) { + for ( i = 0; attrs[i] != NULL; i++ ) + ; + } + if ( i ) { + an = (AttributeName *)pb->pb_op->o_tmpcalloc( i + 1, + sizeof(AttributeName), pb->pb_op->o_tmpmemctx ); + for ( i = 0; attrs[i] != NULL; i++ ) { + an[j].an_desc = NULL; + an[j].an_oc = NULL; + an[j].an_flags = 0; + an[j].an_name.bv_val = attrs[i]; + an[j].an_name.bv_len = strlen( attrs[i] ); + if ( slap_bv2ad( &an[j].an_name, &an[j].an_desc, &pb->pb_rs->sr_text ) == LDAP_SUCCESS ) { + j++; + } + } + an[j].an_name.bv_val = NULL; + an[j].an_name.bv_len = 0; + } + pb->pb_op->ors_attrs = an; + break; + } + case SLAPI_SEARCH_ATTRSONLY: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + pb->pb_op->ors_attrsonly = *((int *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_SEARCH_RESULT_ENTRY: + PBLOCK_ASSERT_OP( pb, 0 ); + rs_replace_entry( pb->pb_op, pb->pb_rs, NULL, (Slapi_Entry *)value ); + /* TODO: Should REP_ENTRY_MODIFIABLE be set? */ + pb->pb_rs->sr_flags |= REP_ENTRY_MUSTBEFREED; + break; + case SLAPI_BIND_RET_SASLCREDS: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_rs->sr_sasldata = (struct berval *)value; + break; + case SLAPI_EXT_OP_REQ_OID: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag == LDAP_REQ_EXTENDED ) { + pb->pb_op->ore_reqoid.bv_val = (char *)value; + pb->pb_op->ore_reqoid.bv_len = strlen((char *)value); + } else { + rc = PBLOCK_ERROR; + } + break; + case SLAPI_EXT_OP_REQ_VALUE: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag == LDAP_REQ_EXTENDED ) + pb->pb_op->ore_reqdata = (struct berval *)value; + else + rc = PBLOCK_ERROR; + break; + case SLAPI_EXT_OP_RET_OID: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_rs->sr_rspoid = (char *)value; + break; + case SLAPI_EXT_OP_RET_VALUE: + PBLOCK_ASSERT_OP( pb, 0 ); + pb->pb_rs->sr_rspdata = (struct berval *)value; + break; + case SLAPI_BIND_METHOD: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag == LDAP_REQ_BIND ) + pb->pb_op->orb_method = *((int *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_BIND_CREDENTIALS: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag == LDAP_REQ_BIND ) + pb->pb_op->orb_cred = *((struct berval *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_COMPARE_TYPE: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag == LDAP_REQ_COMPARE ) { + const char *text; + + pb->pb_op->orc_ava->aa_desc = NULL; + rc = slap_str2ad( (char *)value, &pb->pb_op->orc_ava->aa_desc, &text ); + } else { + rc = PBLOCK_ERROR; + } + break; + case SLAPI_COMPARE_VALUE: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag == LDAP_REQ_COMPARE ) + pb->pb_op->orc_ava->aa_value = *((struct berval *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_ABANDON_MSGID: + PBLOCK_ASSERT_OP( pb, 0 ); + PBLOCK_VALIDATE_IS_INTOP( pb ); + + if ( pb->pb_op->o_tag == LDAP_REQ_ABANDON) + pb->pb_op->orn_msgid = *((int *)value); + else + rc = PBLOCK_ERROR; + break; + case SLAPI_REQUESTOR_ISROOT: + case SLAPI_IS_REPLICATED_OPERATION: + case SLAPI_CONN_AUTHTYPE: + case SLAPI_CONN_AUTHMETHOD: + case SLAPI_IS_INTERNAL_OPERATION: + case SLAPI_X_CONN_IS_UDP: + case SLAPI_CONN_CLIENTIP: + case SLAPI_X_CONN_CLIENTPATH: + case SLAPI_CONN_SERVERIP: + case SLAPI_X_CONN_SERVERPATH: + case SLAPI_X_ADD_STRUCTURAL_CLASS: + /* These parameters cannot be set */ + rc = PBLOCK_ERROR; + break; + default: + rc = pblock_set_default( pb, param, value ); + break; + } + + pblock_unlock( pb ); + + return rc; +} + +static void +pblock_clear( Slapi_PBlock *pb ) +{ + pb->pb_nParams = 1; +} + +static int +pblock_delete_param( Slapi_PBlock *p, int param ) +{ + int i; + + pblock_lock(p); + + for ( i = 0; i < p->pb_nParams; i++ ) { + if ( p->pb_params[i] == param ) { + break; + } + } + + if (i >= p->pb_nParams ) { + pblock_unlock( p ); + return PBLOCK_ERROR; + } + + /* move last parameter to index of deleted parameter */ + if ( p->pb_nParams > 1 ) { + p->pb_params[i] = p->pb_params[p->pb_nParams - 1]; + p->pb_values[i] = p->pb_values[p->pb_nParams - 1]; + } + p->pb_nParams--; + + pblock_unlock( p ); + + return PBLOCK_SUCCESS; +} + +Slapi_PBlock * +slapi_pblock_new(void) +{ + Slapi_PBlock *pb; + + pb = (Slapi_PBlock *) ch_calloc( 1, sizeof(Slapi_PBlock) ); + if ( pb != NULL ) { + ldap_pvt_thread_mutex_init( &pb->pb_mutex ); + + pb->pb_params[0] = SLAPI_IBM_PBLOCK; + pb->pb_values[0].pv_pointer = NULL; + pb->pb_nParams = 1; + pb->pb_conn = NULL; + pb->pb_op = NULL; + pb->pb_rs = NULL; + pb->pb_intop = 0; + } + return pb; +} + +static void +pblock_destroy( Slapi_PBlock *pb ) +{ + LDAPControl **controls = NULL; + LDAPMod **mods = NULL; + char **attrs = NULL; + + assert( pb != NULL ); + + pblock_get_default( pb, SLAPI_RESCONTROLS, (void **)&controls ); + if ( controls != NULL ) { + ldap_controls_free( controls ); + } + + if ( pb->pb_intop ) { + slapi_int_connection_done_pb( pb ); + } else { + pblock_get_default( pb, SLAPI_MODIFY_MODS, (void **)&mods ); + ldap_mods_free( mods, 1 ); + + pblock_get_default( pb, SLAPI_SEARCH_ATTRS, (void **)&attrs ); + if ( attrs != NULL ) + pb->pb_op->o_tmpfree( attrs, pb->pb_op->o_tmpmemctx ); + } + + ldap_pvt_thread_mutex_destroy( &pb->pb_mutex ); + slapi_ch_free( (void **)&pb ); +} + +void +slapi_pblock_destroy( Slapi_PBlock *pb ) +{ + if ( pb != NULL ) { + pblock_destroy( pb ); + } +} + +int +slapi_pblock_get( Slapi_PBlock *pb, int arg, void *value ) +{ + return pblock_get( pb, arg, (void **)value ); +} + +int +slapi_pblock_set( Slapi_PBlock *pb, int arg, void *value ) +{ + return pblock_set( pb, arg, value ); +} + +void +slapi_pblock_clear( Slapi_PBlock *pb ) +{ + pblock_clear( pb ); +} + +int +slapi_pblock_delete_param( Slapi_PBlock *p, int param ) +{ + return pblock_delete_param( p, param ); +} + +/* + * OpenLDAP extension + */ +int +slapi_int_pblock_get_first( Backend *be, Slapi_PBlock **pb ) +{ + assert( pb != NULL ); + *pb = SLAPI_BACKEND_PBLOCK( be ); + return (*pb == NULL ? LDAP_OTHER : LDAP_SUCCESS); +} + +/* + * OpenLDAP extension + */ +int +slapi_int_pblock_get_next( Slapi_PBlock **pb ) +{ + assert( pb != NULL ); + return slapi_pblock_get( *pb, SLAPI_IBM_PBLOCK, pb ); +} + +#endif /* LDAP_SLAPI */ diff --git a/servers/slapd/slapi/slapi_utils.c b/servers/slapd/slapi/slapi_utils.c new file mode 100644 index 0000000..447fe2a --- /dev/null +++ b/servers/slapd/slapi/slapi_utils.c @@ -0,0 +1,3473 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2002-2021 The OpenLDAP Foundation. + * Portions Copyright 1997,2002-2003 IBM Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by IBM Corporation for use in + * IBM products and subsequently ported to OpenLDAP Software by + * Steve Omrani. Additional significant contributors include: + * Luke Howard + */ + +#include "portable.h" + +#include <ac/string.h> +#include <ac/stdarg.h> +#include <ac/ctype.h> +#include <ac/unistd.h> +#include <lutil.h> + +#include <slap.h> +#include <slapi.h> + +#include <netdb.h> + +#ifdef LDAP_SLAPI + +/* + * server start time (should we use a struct timeval also in slapd? + */ +static struct timeval base_time; +ldap_pvt_thread_mutex_t slapi_hn_mutex; +ldap_pvt_thread_mutex_t slapi_time_mutex; + +struct slapi_mutex { + ldap_pvt_thread_mutex_t mutex; +}; + +struct slapi_condvar { + ldap_pvt_thread_cond_t cond; + ldap_pvt_thread_mutex_t mutex; +}; + +static int checkBVString(const struct berval *bv) +{ + ber_len_t i; + + for ( i = 0; i < bv->bv_len; i++ ) { + if ( bv->bv_val[i] == '\0' ) + return 0; + } + if ( bv->bv_val[i] != '\0' ) + return 0; + + return 1; +} + +/* + * This function converts an array of pointers to berval objects to + * an array of berval objects. + */ + +int +bvptr2obj( + struct berval **bvptr, + BerVarray *bvobj, + unsigned *num ) +{ + int rc = LDAP_SUCCESS; + int i; + BerVarray tmpberval; + + if ( bvptr == NULL || *bvptr == NULL ) { + return LDAP_OTHER; + } + + for ( i = 0; bvptr != NULL && bvptr[i] != NULL; i++ ) { + ; /* EMPTY */ + } + if ( num ) + *num = i; + + tmpberval = (BerVarray)slapi_ch_malloc( (i + 1)*sizeof(struct berval)); + if ( tmpberval == NULL ) { + return LDAP_NO_MEMORY; + } + + for ( i = 0; bvptr[i] != NULL; i++ ) { + tmpberval[i].bv_val = bvptr[i]->bv_val; + tmpberval[i].bv_len = bvptr[i]->bv_len; + } + tmpberval[i].bv_val = NULL; + tmpberval[i].bv_len = 0; + + if ( rc == LDAP_SUCCESS ) { + *bvobj = tmpberval; + } + + return rc; +} + +Slapi_Entry * +slapi_str2entry( + char *s, + int flags ) +{ + return str2entry( s ); +} + +char * +slapi_entry2str( + Slapi_Entry *e, + int *len ) +{ + char *ret = NULL; + char *s; + + ldap_pvt_thread_mutex_lock( &entry2str_mutex ); + s = entry2str( e, len ); + if ( s != NULL ) + ret = slapi_ch_strdup( s ); + ldap_pvt_thread_mutex_unlock( &entry2str_mutex ); + + return ret; +} + +char * +slapi_entry_get_dn( Slapi_Entry *e ) +{ + return e->e_name.bv_val; +} + +int +slapi_x_entry_get_id( Slapi_Entry *e ) +{ + return e->e_id; +} + +static int +slapi_int_dn_pretty( struct berval *in, struct berval *out ) +{ + Syntax *syntax = slap_schema.si_syn_distinguishedName; + + assert( syntax != NULL ); + + return (syntax->ssyn_pretty)( syntax, in, out, NULL ); +} + +static int +slapi_int_dn_normalize( struct berval *in, struct berval *out ) +{ + MatchingRule *mr = slap_schema.si_mr_distinguishedNameMatch; + Syntax *syntax = slap_schema.si_syn_distinguishedName; + + assert( mr != NULL ); + + return (mr->smr_normalize)( 0, syntax, mr, in, out, NULL ); +} + +void +slapi_entry_set_dn( + Slapi_Entry *e, + char *ldn ) +{ + struct berval dn = BER_BVNULL; + + dn.bv_val = ldn; + dn.bv_len = strlen( ldn ); + + slapi_int_dn_pretty( &dn, &e->e_name ); + slapi_int_dn_normalize( &dn, &e->e_nname ); +} + +Slapi_Entry * +slapi_entry_dup( Slapi_Entry *e ) +{ + return entry_dup( e ); +} + +int +slapi_entry_attr_delete( + Slapi_Entry *e, + char *type ) +{ + AttributeDescription *ad = NULL; + const char *text; + + if ( slap_str2ad( type, &ad, &text ) != LDAP_SUCCESS ) { + return 1; /* LDAP_NO_SUCH_ATTRIBUTE */ + } + + if ( attr_delete( &e->e_attrs, ad ) == LDAP_SUCCESS ) { + return 0; /* attribute is deleted */ + } else { + return -1; /* something went wrong */ + } +} + +Slapi_Entry * +slapi_entry_alloc( void ) +{ + return (Slapi_Entry *)entry_alloc(); +} + +void +slapi_entry_free( Slapi_Entry *e ) +{ + if ( e != NULL ) + entry_free( e ); +} + +int +slapi_entry_attr_merge( + Slapi_Entry *e, + char *type, + struct berval **vals ) +{ + AttributeDescription *ad = NULL; + const char *text; + BerVarray bv; + int rc; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + rc = bvptr2obj( vals, &bv, NULL ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + rc = attr_merge_normalize( e, ad, bv, NULL ); + ch_free( bv ); + + return rc; +} + +int +slapi_entry_attr_find( + Slapi_Entry *e, + char *type, + Slapi_Attr **attr ) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + *attr = attr_find( e->e_attrs, ad ); + if ( *attr == NULL ) { + return -1; + } + + return 0; +} + +char * +slapi_entry_attr_get_charptr( const Slapi_Entry *e, const char *type ) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + Attribute *attr; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return NULL; + } + + attr = attr_find( e->e_attrs, ad ); + if ( attr == NULL ) { + return NULL; + } + + if ( attr->a_vals != NULL && attr->a_vals[0].bv_len != 0 ) { + const char *p; + + p = slapi_value_get_string( &attr->a_vals[0] ); + if ( p != NULL ) { + return slapi_ch_strdup( p ); + } + } + + return NULL; +} + +int +slapi_entry_attr_get_int( const Slapi_Entry *e, const char *type ) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + Attribute *attr; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + attr = attr_find( e->e_attrs, ad ); + if ( attr == NULL ) { + return 0; + } + + return slapi_value_get_int( attr->a_vals ); +} + +long +slapi_entry_attr_get_long( const Slapi_Entry *e, const char *type ) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + Attribute *attr; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + attr = attr_find( e->e_attrs, ad ); + if ( attr == NULL ) { + return 0; + } + + return slapi_value_get_long( attr->a_vals ); +} + +unsigned int +slapi_entry_attr_get_uint( const Slapi_Entry *e, const char *type ) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + Attribute *attr; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + attr = attr_find( e->e_attrs, ad ); + if ( attr == NULL ) { + return 0; + } + + return slapi_value_get_uint( attr->a_vals ); +} + +unsigned long +slapi_entry_attr_get_ulong( const Slapi_Entry *e, const char *type ) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + Attribute *attr; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + attr = attr_find( e->e_attrs, ad ); + if ( attr == NULL ) { + return 0; + } + + return slapi_value_get_ulong( attr->a_vals ); +} + +int +slapi_entry_attr_hasvalue( Slapi_Entry *e, const char *type, const char *value ) +{ + struct berval bv; + AttributeDescription *ad = NULL; + const char *text; + int rc; + Attribute *attr; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + attr = attr_find( e->e_attrs, ad ); + if ( attr == NULL ) { + return 0; + } + + bv.bv_val = (char *)value; + bv.bv_len = strlen( value ); + + return ( slapi_attr_value_find( attr, &bv ) != -1 ); +} + +void +slapi_entry_attr_set_charptr(Slapi_Entry* e, const char *type, const char *value) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + struct berval bv; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return; + } + + attr_delete ( &e->e_attrs, ad ); + if ( value != NULL ) { + bv.bv_val = (char *)value; + bv.bv_len = strlen(value); + attr_merge_normalize_one( e, ad, &bv, NULL ); + } +} + +void +slapi_entry_attr_set_int( Slapi_Entry* e, const char *type, int l) +{ + char buf[64]; + + snprintf( buf, sizeof( buf ), "%d", l ); + slapi_entry_attr_set_charptr( e, type, buf ); +} + +void +slapi_entry_attr_set_uint( Slapi_Entry* e, const char *type, unsigned int l) +{ + char buf[64]; + + snprintf( buf, sizeof( buf ), "%u", l ); + slapi_entry_attr_set_charptr( e, type, buf ); +} + +void +slapi_entry_attr_set_long(Slapi_Entry* e, const char *type, long l) +{ + char buf[64]; + + snprintf( buf, sizeof( buf ), "%ld", l ); + slapi_entry_attr_set_charptr( e, type, buf ); +} + +void +slapi_entry_attr_set_ulong(Slapi_Entry* e, const char *type, unsigned long l) +{ + char buf[64]; + + snprintf( buf, sizeof( buf ), "%lu", l ); + slapi_entry_attr_set_charptr( e, type, buf ); +} + +int +slapi_is_rootdse( const char *dn ) +{ + return ( dn == NULL || dn[0] == '\0' ); +} + +int +slapi_entry_has_children( const Slapi_Entry *e ) +{ + Slapi_PBlock *pb; + Backend *be = select_backend( (struct berval *)&e->e_nname, 0 ); + int rc, hasSubordinates = 0; + + if ( be == NULL || be->be_has_subordinates == 0 ) { + return 0; + } + + pb = slapi_pblock_new(); + if ( pb == NULL ) { + return 0; + } + slapi_int_connection_init_pb( pb, LDAP_REQ_SEARCH ); + + rc = slapi_pblock_set( pb, SLAPI_TARGET_DN, slapi_entry_get_dn( + (Entry *) e )); + if ( rc == LDAP_SUCCESS ) { + pb->pb_op->o_bd = be; + rc = be->be_has_subordinates( pb->pb_op, (Entry *) e, + &hasSubordinates ); + } + + slapi_pblock_destroy( pb ); + + return ( rc == LDAP_SUCCESS && hasSubordinates == LDAP_COMPARE_TRUE ); +} + +/* + * Return approximate size of the entry rounded to the nearest + * 1K. Only the size of the attribute values are counted in the + * Sun implementation. + * + * http://docs.sun.com/source/816-6701-10/funcref.html#1017388 + */ +size_t slapi_entry_size(Slapi_Entry *e) +{ + size_t size; + Attribute *a; + int i; + + for ( size = 0, a = e->e_attrs; a != NULL; a = a->a_next ) { + for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) { + size += a->a_vals[i].bv_len + 1; + } + } + + size += 1023; + size -= (size % 1024); + + return size; +} + +/* + * Add values to entry. + * + * Returns: + * LDAP_SUCCESS Values added to entry + * LDAP_TYPE_OR_VALUE_EXISTS One or more values exist in entry already + * LDAP_CONSTRAINT_VIOLATION Any other error (odd, but it's the spec) + */ +int +slapi_entry_add_values( Slapi_Entry *e, const char *type, struct berval **vals ) +{ + Modification mod; + const char *text; + int rc; + char textbuf[SLAP_TEXT_BUFLEN]; + + mod.sm_op = LDAP_MOD_ADD; + mod.sm_flags = 0; + mod.sm_desc = NULL; + mod.sm_type.bv_val = (char *)type; + mod.sm_type.bv_len = strlen( type ); + + rc = slap_str2ad( type, &mod.sm_desc, &text ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( vals == NULL ) { + /* Apparently vals can be NULL + * FIXME: sm_values = NULL ? */ + mod.sm_values = (BerVarray)ch_malloc( sizeof(struct berval) ); + mod.sm_values->bv_val = NULL; + mod.sm_numvals = 0; + + } else { + rc = bvptr2obj( vals, &mod.sm_values, &mod.sm_numvals ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_CONSTRAINT_VIOLATION; + } + } + mod.sm_nvalues = NULL; + + rc = modify_add_values( e, &mod, 0, &text, textbuf, sizeof(textbuf) ); + + slapi_ch_free( (void **)&mod.sm_values ); + + return (rc == LDAP_SUCCESS) ? LDAP_SUCCESS : LDAP_CONSTRAINT_VIOLATION; +} + +int +slapi_entry_add_values_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals ) +{ + return slapi_entry_add_values( e, type, vals ); +} + +int +slapi_entry_add_valueset(Slapi_Entry *e, const char *type, Slapi_ValueSet *vs) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + return attr_merge_normalize( e, ad, *vs, NULL ); +} + +int +slapi_entry_delete_values( Slapi_Entry *e, const char *type, struct berval **vals ) +{ + Modification mod; + const char *text; + int rc; + char textbuf[SLAP_TEXT_BUFLEN]; + + mod.sm_op = LDAP_MOD_DELETE; + mod.sm_flags = 0; + mod.sm_desc = NULL; + mod.sm_type.bv_val = (char *)type; + mod.sm_type.bv_len = strlen( type ); + + if ( vals == NULL ) { + /* If vals is NULL, this is a NOOP. */ + return LDAP_SUCCESS; + } + + rc = slap_str2ad( type, &mod.sm_desc, &text ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( vals[0] == NULL ) { + /* SLAPI doco says LDApb_opERATIONS_ERROR but LDAP_OTHER is better */ + return attr_delete( &e->e_attrs, mod.sm_desc ) ? LDAP_OTHER : LDAP_SUCCESS; + } + + rc = bvptr2obj( vals, &mod.sm_values, &mod.sm_numvals ); + if ( rc != LDAP_SUCCESS ) { + return LDAP_CONSTRAINT_VIOLATION; + } + mod.sm_nvalues = NULL; + + rc = modify_delete_values( e, &mod, 0, &text, textbuf, sizeof(textbuf) ); + + slapi_ch_free( (void **)&mod.sm_values ); + + return rc; +} + +int +slapi_entry_delete_values_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals ) +{ + return slapi_entry_delete_values( e, type, vals ); +} + +int +slapi_entry_merge_values_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals ) +{ + return slapi_entry_attr_merge( e, (char *)type, vals ); +} + +int +slapi_entry_add_value(Slapi_Entry *e, const char *type, const Slapi_Value *value) +{ + AttributeDescription *ad = NULL; + int rc; + const char *text; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + rc = attr_merge_normalize_one( e, ad, (Slapi_Value *)value, NULL ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + return 0; +} + +int +slapi_entry_add_string(Slapi_Entry *e, const char *type, const char *value) +{ + Slapi_Value val; + + val.bv_val = (char *)value; + val.bv_len = strlen( value ); + + return slapi_entry_add_value( e, type, &val ); +} + +int +slapi_entry_delete_string(Slapi_Entry *e, const char *type, const char *value) +{ + Slapi_Value *vals[2]; + Slapi_Value val; + + val.bv_val = (char *)value; + val.bv_len = strlen( value ); + vals[0] = &val; + vals[1] = NULL; + + return slapi_entry_delete_values_sv( e, type, vals ); +} + +int +slapi_entry_attr_merge_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals ) +{ + return slapi_entry_attr_merge( e, (char *)type, vals ); +} + +int +slapi_entry_first_attr( const Slapi_Entry *e, Slapi_Attr **attr ) +{ + if ( e == NULL ) { + return -1; + } + + *attr = e->e_attrs; + + return ( *attr != NULL ) ? 0 : -1; +} + +int +slapi_entry_next_attr( const Slapi_Entry *e, Slapi_Attr *prevattr, Slapi_Attr **attr ) +{ + if ( e == NULL ) { + return -1; + } + + if ( prevattr == NULL ) { + return -1; + } + + *attr = prevattr->a_next; + + return ( *attr != NULL ) ? 0 : -1; +} + +int +slapi_entry_attr_replace_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals ) +{ + AttributeDescription *ad = NULL; + const char *text; + int rc; + BerVarray bv; + + rc = slap_str2ad( type, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + attr_delete( &e->e_attrs, ad ); + + rc = bvptr2obj( vals, &bv, NULL ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + rc = attr_merge_normalize( e, ad, bv, NULL ); + slapi_ch_free( (void **)&bv ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + return 0; +} + +/* + * FIXME -- The caller must free the allocated memory. + * In Netscape they do not have to. + */ +int +slapi_attr_get_values( + Slapi_Attr *attr, + struct berval ***vals ) +{ + int i, j; + struct berval **bv; + + if ( attr == NULL ) { + return 1; + } + + for ( i = 0; attr->a_vals[i].bv_val != NULL; i++ ) { + ; /* EMPTY */ + } + + bv = (struct berval **)ch_malloc( (i + 1) * sizeof(struct berval *) ); + for ( j = 0; j < i; j++ ) { + bv[j] = ber_dupbv( NULL, &attr->a_vals[j] ); + } + bv[j] = NULL; + + *vals = (struct berval **)bv; + + return 0; +} + +char * +slapi_dn_normalize( char *dn ) +{ + struct berval bdn; + struct berval pdn; + + assert( dn != NULL ); + + bdn.bv_val = dn; + bdn.bv_len = strlen( dn ); + + if ( slapi_int_dn_pretty( &bdn, &pdn ) != LDAP_SUCCESS ) { + return NULL; + } + + return pdn.bv_val; +} + +char * +slapi_dn_normalize_case( char *dn ) +{ + struct berval bdn; + struct berval ndn; + + assert( dn != NULL ); + + bdn.bv_val = dn; + bdn.bv_len = strlen( dn ); + + if ( slapi_int_dn_normalize( &bdn, &ndn ) != LDAP_SUCCESS ) { + return NULL; + } + + return ndn.bv_val; +} + +int +slapi_dn_issuffix( + char *dn, + char *suffix ) +{ + struct berval bdn, ndn; + struct berval bsuffix, nsuffix; + int rc; + + assert( dn != NULL ); + assert( suffix != NULL ); + + bdn.bv_val = dn; + bdn.bv_len = strlen( dn ); + + bsuffix.bv_val = suffix; + bsuffix.bv_len = strlen( suffix ); + + if ( dnNormalize( 0, NULL, NULL, &bdn, &ndn, NULL ) != LDAP_SUCCESS ) { + return 0; + } + + if ( dnNormalize( 0, NULL, NULL, &bsuffix, &nsuffix, NULL ) + != LDAP_SUCCESS ) + { + slapi_ch_free( (void **)&ndn.bv_val ); + return 0; + } + + rc = dnIsSuffix( &ndn, &nsuffix ); + + slapi_ch_free( (void **)&ndn.bv_val ); + slapi_ch_free( (void **)&nsuffix.bv_val ); + + return rc; +} + +int +slapi_dn_isparent( + const char *parentdn, + const char *childdn ) +{ + struct berval assertedParentDN, normalizedAssertedParentDN; + struct berval childDN, normalizedChildDN; + struct berval normalizedParentDN; + int match; + + assert( parentdn != NULL ); + assert( childdn != NULL ); + + assertedParentDN.bv_val = (char *)parentdn; + assertedParentDN.bv_len = strlen( parentdn ); + + if ( dnNormalize( 0, NULL, NULL, &assertedParentDN, + &normalizedAssertedParentDN, NULL ) != LDAP_SUCCESS ) + { + return 0; + } + + childDN.bv_val = (char *)childdn; + childDN.bv_len = strlen( childdn ); + + if ( dnNormalize( 0, NULL, NULL, &childDN, + &normalizedChildDN, NULL ) != LDAP_SUCCESS ) + { + slapi_ch_free( (void **)&normalizedAssertedParentDN.bv_val ); + return 0; + } + + dnParent( &normalizedChildDN, &normalizedParentDN ); + + if ( dnMatch( &match, 0, slap_schema.si_syn_distinguishedName, NULL, + &normalizedParentDN, (void *)&normalizedAssertedParentDN ) != LDAP_SUCCESS ) + { + match = -1; + } + + slapi_ch_free( (void **)&normalizedAssertedParentDN.bv_val ); + slapi_ch_free( (void **)&normalizedChildDN.bv_val ); + + return ( match == 0 ); +} + +/* + * Returns DN of the parent entry, or NULL if the DN is + * an empty string or NULL, or has no parent. + */ +char * +slapi_dn_parent( const char *_dn ) +{ + struct berval dn, prettyDN; + struct berval parentDN; + char *ret; + + if ( _dn == NULL ) { + return NULL; + } + + dn.bv_val = (char *)_dn; + dn.bv_len = strlen( _dn ); + + if ( dn.bv_len == 0 ) { + return NULL; + } + + if ( dnPretty( NULL, &dn, &prettyDN, NULL ) != LDAP_SUCCESS ) { + return NULL; + } + + dnParent( &prettyDN, &parentDN ); /* in-place */ + + if ( parentDN.bv_len == 0 ) { + slapi_ch_free_string( &prettyDN.bv_val ); + return NULL; + } + + ret = slapi_ch_strdup( parentDN.bv_val ); + slapi_ch_free_string( &prettyDN.bv_val ); + + return ret; +} + +int slapi_dn_isbesuffix( Slapi_PBlock *pb, char *ldn ) +{ + struct berval ndn; + Backend *be; + + if ( slapi_is_rootdse( ldn ) ) { + return 0; + } + + /* according to spec should already be normalized */ + ndn.bv_len = strlen( ldn ); + ndn.bv_val = ldn; + + be = select_backend( &pb->pb_op->o_req_ndn, 0 ); + if ( be == NULL ) { + return 0; + } + + return be_issuffix( be, &ndn ); +} + +/* + * Returns DN of the parent entry; or NULL if the DN is + * an empty string, if the DN has no parent, or if the + * DN is the suffix of the backend database + */ +char *slapi_dn_beparent( Slapi_PBlock *pb, const char *ldn ) +{ + Backend *be; + struct berval dn, prettyDN; + struct berval normalizedDN, parentDN; + char *parent = NULL; + + if ( pb == NULL ) { + return NULL; + } + + PBLOCK_ASSERT_OP( pb, 0 ); + + if ( slapi_is_rootdse( ldn ) ) { + return NULL; + } + + dn.bv_val = (char *)ldn; + dn.bv_len = strlen( ldn ); + + if ( dnPrettyNormal( NULL, &dn, &prettyDN, &normalizedDN, NULL ) != LDAP_SUCCESS ) { + return NULL; + } + + be = select_backend( &pb->pb_op->o_req_ndn, 0 ); + + if ( be == NULL || be_issuffix( be, &normalizedDN ) == 0 ) { + dnParent( &prettyDN, &parentDN ); + + if ( parentDN.bv_len != 0 ) + parent = slapi_ch_strdup( parentDN.bv_val ); + } + + slapi_ch_free_string( &prettyDN.bv_val ); + slapi_ch_free_string( &normalizedDN.bv_val ); + + return parent; +} + +char * +slapi_dn_ignore_case( char *dn ) +{ + return slapi_dn_normalize_case( dn ); +} + +char * +slapi_ch_malloc( unsigned long size ) +{ + return ch_malloc( size ); +} + +void +slapi_ch_free( void **ptr ) +{ + if ( ptr == NULL || *ptr == NULL ) + return; + ch_free( *ptr ); + *ptr = NULL; +} + +void +slapi_ch_free_string( char **ptr ) +{ + slapi_ch_free( (void **)ptr ); +} + +void +slapi_ch_array_free( char **arrayp ) +{ + char **p; + + if ( arrayp != NULL ) { + for ( p = arrayp; *p != NULL; p++ ) { + slapi_ch_free( (void **)p ); + } + slapi_ch_free( (void **)&arrayp ); + } +} + +struct berval * +slapi_ch_bvdup(const struct berval *v) +{ + return ber_dupbv(NULL, (struct berval *)v); +} + +struct berval ** +slapi_ch_bvecdup(const struct berval **v) +{ + int i; + struct berval **rv; + + if ( v == NULL ) { + return NULL; + } + + for ( i = 0; v[i] != NULL; i++ ) + ; + + rv = (struct berval **) slapi_ch_malloc( (i + 1) * sizeof(struct berval *) ); + + for ( i = 0; v[i] != NULL; i++ ) { + rv[i] = slapi_ch_bvdup( v[i] ); + } + rv[i] = NULL; + + return rv; +} + +char * +slapi_ch_calloc( + unsigned long nelem, + unsigned long size ) +{ + return ch_calloc( nelem, size ); +} + +char * +slapi_ch_realloc( + char *block, + unsigned long size ) +{ + return ch_realloc( block, size ); +} + +char * +slapi_ch_strdup( const char *s ) +{ + return ch_strdup( s ); +} + +size_t +slapi_ch_stlen( const char *s ) +{ + return strlen( s ); +} + +int +slapi_control_present( + LDAPControl **controls, + char *oid, + struct berval **val, + int *iscritical ) +{ + int i; + int rc = 0; + + if ( val ) { + *val = NULL; + } + + if ( iscritical ) { + *iscritical = 0; + } + + for ( i = 0; controls != NULL && controls[i] != NULL; i++ ) { + if ( strcmp( controls[i]->ldctl_oid, oid ) != 0 ) { + continue; + } + + rc = 1; + if ( controls[i]->ldctl_value.bv_len != 0 ) { + if ( val ) { + *val = &controls[i]->ldctl_value; + } + } + + if ( iscritical ) { + *iscritical = controls[i]->ldctl_iscritical; + } + + break; + } + + return rc; +} + +static void +slapControlMask2SlapiControlOp(slap_mask_t slap_mask, + unsigned long *slapi_mask) +{ + *slapi_mask = SLAPI_OPERATION_NONE; + + if ( slap_mask & SLAP_CTRL_ABANDON ) + *slapi_mask |= SLAPI_OPERATION_ABANDON; + + if ( slap_mask & SLAP_CTRL_ADD ) + *slapi_mask |= SLAPI_OPERATION_ADD; + + if ( slap_mask & SLAP_CTRL_BIND ) + *slapi_mask |= SLAPI_OPERATION_BIND; + + if ( slap_mask & SLAP_CTRL_COMPARE ) + *slapi_mask |= SLAPI_OPERATION_COMPARE; + + if ( slap_mask & SLAP_CTRL_DELETE ) + *slapi_mask |= SLAPI_OPERATION_DELETE; + + if ( slap_mask & SLAP_CTRL_MODIFY ) + *slapi_mask |= SLAPI_OPERATION_MODIFY; + + if ( slap_mask & SLAP_CTRL_RENAME ) + *slapi_mask |= SLAPI_OPERATION_MODDN; + + if ( slap_mask & SLAP_CTRL_SEARCH ) + *slapi_mask |= SLAPI_OPERATION_SEARCH; + + if ( slap_mask & SLAP_CTRL_UNBIND ) + *slapi_mask |= SLAPI_OPERATION_UNBIND; +} + +static void +slapiControlOp2SlapControlMask(unsigned long slapi_mask, + slap_mask_t *slap_mask) +{ + *slap_mask = 0; + + if ( slapi_mask & SLAPI_OPERATION_BIND ) + *slap_mask |= SLAP_CTRL_BIND; + + if ( slapi_mask & SLAPI_OPERATION_UNBIND ) + *slap_mask |= SLAP_CTRL_UNBIND; + + if ( slapi_mask & SLAPI_OPERATION_SEARCH ) + *slap_mask |= SLAP_CTRL_SEARCH; + + if ( slapi_mask & SLAPI_OPERATION_MODIFY ) + *slap_mask |= SLAP_CTRL_MODIFY; + + if ( slapi_mask & SLAPI_OPERATION_ADD ) + *slap_mask |= SLAP_CTRL_ADD; + + if ( slapi_mask & SLAPI_OPERATION_DELETE ) + *slap_mask |= SLAP_CTRL_DELETE; + + if ( slapi_mask & SLAPI_OPERATION_MODDN ) + *slap_mask |= SLAP_CTRL_RENAME; + + if ( slapi_mask & SLAPI_OPERATION_COMPARE ) + *slap_mask |= SLAP_CTRL_COMPARE; + + if ( slapi_mask & SLAPI_OPERATION_ABANDON ) + *slap_mask |= SLAP_CTRL_ABANDON; + + *slap_mask |= SLAP_CTRL_GLOBAL; +} + +static int +slapi_int_parse_control( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + /* Plugins must deal with controls themselves. */ + + return LDAP_SUCCESS; +} + +void +slapi_register_supported_control( + char *controloid, + unsigned long controlops ) +{ + slap_mask_t controlmask; + + slapiControlOp2SlapControlMask( controlops, &controlmask ); + + register_supported_control( controloid, controlmask, NULL, slapi_int_parse_control, NULL ); +} + +int +slapi_get_supported_controls( + char ***ctrloidsp, + unsigned long **ctrlopsp ) +{ + int i, rc; + + rc = get_supported_controls( ctrloidsp, (slap_mask_t **)ctrlopsp ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + for ( i = 0; (*ctrloidsp)[i] != NULL; i++ ) { + /* In place, naughty. */ + slapControlMask2SlapiControlOp( (*ctrlopsp)[i], &((*ctrlopsp)[i]) ); + } + + return LDAP_SUCCESS; +} + +LDAPControl * +slapi_dup_control( LDAPControl *ctrl ) +{ + LDAPControl *ret; + + ret = (LDAPControl *)slapi_ch_malloc( sizeof(*ret) ); + ret->ldctl_oid = slapi_ch_strdup( ctrl->ldctl_oid ); + ber_dupbv( &ret->ldctl_value, &ctrl->ldctl_value ); + ret->ldctl_iscritical = ctrl->ldctl_iscritical; + + return ret; +} + +void +slapi_register_supported_saslmechanism( char *mechanism ) +{ + /* FIXME -- can not add saslmechanism to OpenLDAP dynamically */ + slapi_log_error( SLAPI_LOG_FATAL, "slapi_register_supported_saslmechanism", + "OpenLDAP does not support dynamic registration of SASL mechanisms\n" ); +} + +char ** +slapi_get_supported_saslmechanisms( void ) +{ + /* FIXME -- can not get the saslmechanism without a connection. */ + slapi_log_error( SLAPI_LOG_FATAL, "slapi_get_supported_saslmechanisms", + "can not get the SASL mechanism list " + "without a connection\n" ); + return NULL; +} + +char ** +slapi_get_supported_extended_ops( void ) +{ + int i, j, k; + char **ppExtOpOID = NULL; + int numExtOps = 0; + + for ( i = 0; get_supported_extop( i ) != NULL; i++ ) { + ; + } + + for ( j = 0; slapi_int_get_supported_extop( j ) != NULL; j++ ) { + ; + } + + numExtOps = i + j; + if ( numExtOps == 0 ) { + return NULL; + } + + ppExtOpOID = (char **)slapi_ch_malloc( (numExtOps + 1) * sizeof(char *) ); + for ( k = 0; k < i; k++ ) { + struct berval *bv; + + bv = get_supported_extop( k ); + assert( bv != NULL ); + + ppExtOpOID[ k ] = bv->bv_val; + } + + for ( ; k < j; k++ ) { + struct berval *bv; + + bv = slapi_int_get_supported_extop( k ); + assert( bv != NULL ); + + ppExtOpOID[ i + k ] = bv->bv_val; + } + ppExtOpOID[ i + k ] = NULL; + + return ppExtOpOID; +} + +void +slapi_send_ldap_result( + Slapi_PBlock *pb, + int err, + char *matched, + char *text, + int nentries, + struct berval **urls ) +{ + SlapReply *rs; + + PBLOCK_ASSERT_OP( pb, 0 ); + + rs = pb->pb_rs; + + rs->sr_err = err; + rs->sr_matched = matched; + rs->sr_text = text; + rs->sr_ref = NULL; + + if ( err == LDAP_SASL_BIND_IN_PROGRESS ) { + send_ldap_sasl( pb->pb_op, rs ); + } else if ( rs->sr_rspoid != NULL ) { + send_ldap_extended( pb->pb_op, rs ); + } else { + if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) + rs->sr_nentries = nentries; + if ( urls != NULL ) + bvptr2obj( urls, &rs->sr_ref, NULL ); + + send_ldap_result( pb->pb_op, rs ); + + if ( urls != NULL ) + slapi_ch_free( (void **)&rs->sr_ref ); + } +} + +int +slapi_send_ldap_search_entry( + Slapi_PBlock *pb, + Slapi_Entry *e, + LDAPControl **ectrls, + char **attrs, + int attrsonly ) +{ + SlapReply rs = { REP_SEARCH }; + int i = 0, j = 0; + AttributeName *an = NULL; + const char *text; + int rc; + + assert( pb->pb_op != NULL ); + + if ( attrs != NULL ) { + for ( i = 0; attrs[ i ] != NULL; i++ ) { + ; /* empty */ + } + } + + if ( i ) { + an = (AttributeName *) slapi_ch_calloc( i + 1, sizeof(AttributeName) ); + for ( i = 0; attrs[i] != NULL; i++ ) { + an[j].an_name.bv_val = attrs[i]; + an[j].an_name.bv_len = strlen( attrs[i] ); + an[j].an_desc = NULL; + if ( slap_bv2ad( &an[j].an_name, &an[j].an_desc, &text ) == LDAP_SUCCESS) { + j++; + } + } + an[j].an_name.bv_len = 0; + an[j].an_name.bv_val = NULL; + } + + rs.sr_err = LDAP_SUCCESS; + rs.sr_matched = NULL; + rs.sr_text = NULL; + rs.sr_ref = NULL; + rs.sr_ctrls = ectrls; + rs.sr_attrs = an; + rs.sr_operational_attrs = NULL; + rs.sr_entry = e; + rs.sr_v2ref = NULL; + rs.sr_flags = 0; + + rc = send_search_entry( pb->pb_op, &rs ); + + slapi_ch_free( (void **)&an ); + + return rc; +} + +int +slapi_send_ldap_search_reference( + Slapi_PBlock *pb, + Slapi_Entry *e, + struct berval **references, + LDAPControl **ectrls, + struct berval **v2refs + ) +{ + SlapReply rs = { REP_SEARCHREF }; + int rc; + + rs.sr_err = LDAP_SUCCESS; + rs.sr_matched = NULL; + rs.sr_text = NULL; + + rc = bvptr2obj( references, &rs.sr_ref, NULL ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + rs.sr_ctrls = ectrls; + rs.sr_attrs = NULL; + rs.sr_operational_attrs = NULL; + rs.sr_entry = e; + + if ( v2refs != NULL ) { + rc = bvptr2obj( v2refs, &rs.sr_v2ref, NULL ); + if ( rc != LDAP_SUCCESS ) { + slapi_ch_free( (void **)&rs.sr_ref ); + return rc; + } + } else { + rs.sr_v2ref = NULL; + } + + rc = send_search_reference( pb->pb_op, &rs ); + + slapi_ch_free( (void **)&rs.sr_ref ); + slapi_ch_free( (void **)&rs.sr_v2ref ); + + return rc; +} + +Slapi_Filter * +slapi_str2filter( char *str ) +{ + return str2filter( str ); +} + +void +slapi_filter_free( + Slapi_Filter *f, + int recurse ) +{ + filter_free( f ); +} + +Slapi_Filter * +slapi_filter_dup( Slapi_Filter *filter ) +{ + return filter_dup( filter, NULL ); +} + +int +slapi_filter_get_choice( Slapi_Filter *f ) +{ + int rc; + + if ( f != NULL ) { + rc = f->f_choice; + } else { + rc = 0; + } + + return rc; +} + +int +slapi_filter_get_ava( + Slapi_Filter *f, + char **type, + struct berval **bval ) +{ + int ftype; + int rc = LDAP_SUCCESS; + + assert( type != NULL ); + assert( bval != NULL ); + + *type = NULL; + *bval = NULL; + + ftype = f->f_choice; + if ( ftype == LDAP_FILTER_EQUALITY + || ftype == LDAP_FILTER_GE + || ftype == LDAP_FILTER_LE + || ftype == LDAP_FILTER_APPROX ) { + /* + * According to the SLAPI Reference Manual these are + * not duplicated. + */ + *type = f->f_un.f_un_ava->aa_desc->ad_cname.bv_val; + *bval = &f->f_un.f_un_ava->aa_value; + } else { /* filter type not supported */ + rc = -1; + } + + return rc; +} + +Slapi_Filter * +slapi_filter_list_first( Slapi_Filter *f ) +{ + int ftype; + + if ( f == NULL ) { + return NULL; + } + + ftype = f->f_choice; + if ( ftype == LDAP_FILTER_AND + || ftype == LDAP_FILTER_OR + || ftype == LDAP_FILTER_NOT ) { + return (Slapi_Filter *)f->f_list; + } else { + return NULL; + } +} + +Slapi_Filter * +slapi_filter_list_next( + Slapi_Filter *f, + Slapi_Filter *fprev ) +{ + int ftype; + + if ( f == NULL ) { + return NULL; + } + + ftype = f->f_choice; + if ( ftype == LDAP_FILTER_AND + || ftype == LDAP_FILTER_OR + || ftype == LDAP_FILTER_NOT ) + { + return fprev->f_next; + } + + return NULL; +} + +int +slapi_filter_get_attribute_type( Slapi_Filter *f, char **type ) +{ + if ( f == NULL ) { + return -1; + } + + switch ( f->f_choice ) { + case LDAP_FILTER_GE: + case LDAP_FILTER_LE: + case LDAP_FILTER_EQUALITY: + case LDAP_FILTER_APPROX: + *type = f->f_av_desc->ad_cname.bv_val; + break; + case LDAP_FILTER_SUBSTRINGS: + *type = f->f_sub_desc->ad_cname.bv_val; + break; + case LDAP_FILTER_PRESENT: + *type = f->f_desc->ad_cname.bv_val; + break; + case LDAP_FILTER_EXT: + *type = f->f_mr_desc->ad_cname.bv_val; + break; + default: + /* Complex filters need not apply. */ + *type = NULL; + return -1; + } + + return 0; +} + +int +slapi_x_filter_set_attribute_type( Slapi_Filter *f, const char *type ) +{ + AttributeDescription **adp, *ad = NULL; + const char *text; + int rc; + + if ( f == NULL ) { + return -1; + } + + switch ( f->f_choice ) { + case LDAP_FILTER_GE: + case LDAP_FILTER_LE: + case LDAP_FILTER_EQUALITY: + case LDAP_FILTER_APPROX: + adp = &f->f_av_desc; + break; + case LDAP_FILTER_SUBSTRINGS: + adp = &f->f_sub_desc; + break; + case LDAP_FILTER_PRESENT: + adp = &f->f_desc; + break; + case LDAP_FILTER_EXT: + adp = &f->f_mr_desc; + break; + default: + /* Complex filters need not apply. */ + return -1; + } + + rc = slap_str2ad( type, &ad, &text ); + if ( rc == LDAP_SUCCESS ) + *adp = ad; + + return ( rc == LDAP_SUCCESS ) ? 0 : -1; +} + +int +slapi_filter_get_subfilt( Slapi_Filter *f, char **type, char **initial, + char ***any, char **final ) +{ + int i; + + if ( f->f_choice != LDAP_FILTER_SUBSTRINGS ) { + return -1; + } + + /* + * The caller shouldn't free but we can't return an + * array of char *s from an array of bervals without + * allocating memory, so we may as well be consistent. + * XXX + */ + *type = f->f_sub_desc->ad_cname.bv_val; + *initial = f->f_sub_initial.bv_val ? slapi_ch_strdup(f->f_sub_initial.bv_val) : NULL; + if ( f->f_sub_any != NULL ) { + for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) + ; + *any = (char **)slapi_ch_malloc( (i + 1) * sizeof(char *) ); + for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) { + (*any)[i] = slapi_ch_strdup(f->f_sub_any[i].bv_val); + } + (*any)[i] = NULL; + } else { + *any = NULL; + } + *final = f->f_sub_final.bv_val ? slapi_ch_strdup(f->f_sub_final.bv_val) : NULL; + + return 0; +} + +Slapi_Filter * +slapi_filter_join( int ftype, Slapi_Filter *f1, Slapi_Filter *f2 ) +{ + Slapi_Filter *f = NULL; + + if ( ftype == LDAP_FILTER_AND || + ftype == LDAP_FILTER_OR || + ftype == LDAP_FILTER_NOT ) + { + f = (Slapi_Filter *)slapi_ch_malloc( sizeof(*f) ); + f->f_choice = ftype; + f->f_list = f1; + f->f_list->f_next = f2; + f->f_next = NULL; + } + + return f; +} + +int +slapi_x_filter_append( int ftype, + Slapi_Filter **pContainingFilter, /* NULL on first call */ + Slapi_Filter **pNextFilter, + Slapi_Filter *filterToAppend ) +{ + if ( ftype == LDAP_FILTER_AND || + ftype == LDAP_FILTER_OR || + ftype == LDAP_FILTER_NOT ) + { + if ( *pContainingFilter == NULL ) { + *pContainingFilter = (Slapi_Filter *)slapi_ch_malloc( sizeof(Slapi_Filter) ); + (*pContainingFilter)->f_choice = ftype; + (*pContainingFilter)->f_list = filterToAppend; + (*pContainingFilter)->f_next = NULL; + } else { + if ( (*pContainingFilter)->f_choice != ftype ) { + /* Sanity check */ + return -1; + } + (*pNextFilter)->f_next = filterToAppend; + } + *pNextFilter = filterToAppend; + + return 0; + } + return -1; +} + +int +slapi_filter_test( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Filter *f, + int verify_access ) +{ + Operation *op; + int rc; + + if ( f == NULL ) { + /* spec says return zero if no filter. */ + return 0; + } + + if ( verify_access ) { + op = pb->pb_op; + if ( op == NULL ) + return LDAP_PARAM_ERROR; + } else { + op = NULL; + } + + /* + * According to acl.c it is safe to call test_filter() with + * NULL arguments... + */ + rc = test_filter( op, e, f ); + switch (rc) { + case LDAP_COMPARE_TRUE: + rc = 0; + break; + case LDAP_COMPARE_FALSE: + break; + case SLAPD_COMPARE_UNDEFINED: + rc = LDAP_OTHER; + break; + case LDAP_PROTOCOL_ERROR: + /* filter type unknown: spec says return -1 */ + rc = -1; + break; + } + + return rc; +} + +int +slapi_filter_test_simple( Slapi_Entry *e, Slapi_Filter *f) +{ + return slapi_filter_test( NULL, e, f, 0 ); +} + +int +slapi_filter_apply( Slapi_Filter *f, FILTER_APPLY_FN fn, void *arg, int *error_code ) +{ + switch ( f->f_choice ) { + case LDAP_FILTER_AND: + case LDAP_FILTER_NOT: + case LDAP_FILTER_OR: { + int rc; + + /* + * FIXME: altering f; should we use a temporary? + */ + for ( f = f->f_list; f != NULL; f = f->f_next ) { + rc = slapi_filter_apply( f, fn, arg, error_code ); + if ( rc != 0 ) { + return rc; + } + if ( *error_code == SLAPI_FILTER_SCAN_NOMORE ) { + break; + } + } + break; + } + case LDAP_FILTER_EQUALITY: + case LDAP_FILTER_SUBSTRINGS: + case LDAP_FILTER_GE: + case LDAP_FILTER_LE: + case LDAP_FILTER_PRESENT: + case LDAP_FILTER_APPROX: + case LDAP_FILTER_EXT: + *error_code = fn( f, arg ); + break; + default: + *error_code = SLAPI_FILTER_UNKNOWN_FILTER_TYPE; + } + + if ( *error_code == SLAPI_FILTER_SCAN_NOMORE || + *error_code == SLAPI_FILTER_SCAN_CONTINUE ) { + return 0; + } + + return -1; +} + +int +slapi_pw_find( + struct berval **vals, + struct berval *v ) +{ + int i; + + if( ( vals == NULL ) || ( v == NULL ) ) + return 1; + + for ( i = 0; vals[i] != NULL; i++ ) { + if ( !lutil_passwd( vals[i], v, NULL, NULL ) ) + return 0; + } + + return 1; +} + +/* Get connected client IP address. + * + * The user must free the returned client IP after its use. + * Compatible with IBM Tivoli call. + * + * Errors: + * * LDAP_PARAM_ERROR - If the pb parameter is null. + * * LDAP_OPERATIONS_ERROR - If the API encounters error processing the request. + * * LDAP_NO_MEMORY - Failed to allocate required memory. + */ +int +slapi_get_client_ip(Slapi_PBlock *pb, char **clientIP) +{ + char *s = NULL; + + if(pb == NULL || pb->pb_conn == NULL) return(LDAP_PARAM_ERROR); + if((s = (char *) slapi_ch_malloc(pb->pb_conn->c_peer_name.bv_len + 1)) == NULL) { + return(LDAP_NO_MEMORY); + } + + memcpy(s, pb->pb_conn->c_peer_name.bv_val, pb->pb_conn->c_peer_name.bv_len); + + s[pb->pb_conn->c_peer_name.bv_len] = 0; + + *clientIP = s; + + return(LDAP_SUCCESS); +} + +/* Free previously allocated client IP address. */ +void +slapi_free_client_ip(char **clientIP) +{ + slapi_ch_free((void **) clientIP); +} + +#define MAX_HOSTNAME 512 + +char * +slapi_get_hostname( void ) +{ + char *hn = NULL; + static int been_here = 0; + static char *static_hn = NULL; + + ldap_pvt_thread_mutex_lock( &slapi_hn_mutex ); + if ( !been_here ) { + static_hn = (char *)slapi_ch_malloc( MAX_HOSTNAME ); + if ( static_hn == NULL) { + slapi_log_error( SLAPI_LOG_FATAL, "slapi_get_hostname", + "Cannot allocate memory for hostname\n" ); + static_hn = NULL; + ldap_pvt_thread_mutex_unlock( &slapi_hn_mutex ); + + return hn; + + } else { + if ( gethostname( static_hn, MAX_HOSTNAME ) != 0 ) { + slapi_log_error( SLAPI_LOG_FATAL, + "SLAPI", + "can't get hostname\n" ); + slapi_ch_free( (void **)&static_hn ); + static_hn = NULL; + ldap_pvt_thread_mutex_unlock( &slapi_hn_mutex ); + + return hn; + + } else { + been_here = 1; + } + } + } + ldap_pvt_thread_mutex_unlock( &slapi_hn_mutex ); + + hn = ch_strdup( static_hn ); + + return hn; +} + +/* + * FIXME: this should go in an appropriate header ... + */ +extern int slapi_int_log_error( int level, char *subsystem, char *fmt, va_list arglist ); + +int +slapi_log_error( + int severity, + char *subsystem, + char *fmt, + ... ) +{ + int rc = LDAP_SUCCESS; + va_list arglist; + + va_start( arglist, fmt ); + rc = slapi_int_log_error( severity, subsystem, fmt, arglist ); + va_end( arglist ); + + return rc; +} + + +unsigned long +slapi_timer_current_time( void ) +{ + static int first_time = 1; +#if !defined (_WIN32) + struct timeval now; + unsigned long ret; + + ldap_pvt_thread_mutex_lock( &slapi_time_mutex ); + if (first_time) { + first_time = 0; + gettimeofday( &base_time, NULL ); + } + gettimeofday( &now, NULL ); + ret = ( now.tv_sec - base_time.tv_sec ) * 1000000 + + (now.tv_usec - base_time.tv_usec); + ldap_pvt_thread_mutex_unlock( &slapi_time_mutex ); + + return ret; + + /* + * Ain't it better? + return (slap_get_time() - starttime) * 1000000; + */ +#else /* _WIN32 */ + LARGE_INTEGER now; + + if ( first_time ) { + first_time = 0; + performance_counter_present = QueryPerformanceCounter( &base_time ); + QueryPerformanceFrequency( &performance_freq ); + } + + if ( !performance_counter_present ) + return 0; + + QueryPerformanceCounter( &now ); + return (1000000*(now.QuadPart-base_time.QuadPart))/performance_freq.QuadPart; +#endif /* _WIN32 */ +} + +/* + * FIXME ? + */ +unsigned long +slapi_timer_get_time( char *label ) +{ + unsigned long start = slapi_timer_current_time(); + printf("%10ld %10d usec %s\n", start, 0, label); + return start; +} + +/* + * FIXME ? + */ +void +slapi_timer_elapsed_time( + char *label, + unsigned long start ) +{ + unsigned long stop = slapi_timer_current_time(); + printf ("%10ld %10ld usec %s\n", stop, stop - start, label); +} + +void +slapi_free_search_results_internal( Slapi_PBlock *pb ) +{ + Slapi_Entry **entries; + int k = 0, nEnt = 0; + + slapi_pblock_get( pb, SLAPI_NENTRIES, &nEnt ); + slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries ); + if ( nEnt == 0 || entries == NULL ) { + return; + } + + for ( k = 0; k < nEnt; k++ ) { + slapi_entry_free( entries[k] ); + entries[k] = NULL; + } + + slapi_ch_free( (void **)&entries ); +} + +int slapi_is_connection_ssl( Slapi_PBlock *pb, int *isSSL ) +{ + if ( pb == NULL ) + return LDAP_PARAM_ERROR; + + if ( pb->pb_conn == NULL ) + return LDAP_PARAM_ERROR; + +#ifdef HAVE_TLS + *isSSL = pb->pb_conn->c_is_tls; +#else + *isSSL = 0; +#endif + + return LDAP_SUCCESS; +} + +/* + * DS 5.x compatability API follow + */ + +int slapi_attr_get_flags( const Slapi_Attr *attr, unsigned long *flags ) +{ + AttributeType *at; + + if ( attr == NULL ) + return LDAP_PARAM_ERROR; + + at = attr->a_desc->ad_type; + + *flags = SLAPI_ATTR_FLAG_STD_ATTR; + + if ( is_at_single_value( at ) ) + *flags |= SLAPI_ATTR_FLAG_SINGLE; + if ( is_at_operational( at ) ) + *flags |= SLAPI_ATTR_FLAG_OPATTR; + if ( is_at_obsolete( at ) ) + *flags |= SLAPI_ATTR_FLAG_OBSOLETE; + if ( is_at_collective( at ) ) + *flags |= SLAPI_ATTR_FLAG_COLLECTIVE; + if ( is_at_no_user_mod( at ) ) + *flags |= SLAPI_ATTR_FLAG_NOUSERMOD; + + return LDAP_SUCCESS; +} + +int slapi_attr_flag_is_set( const Slapi_Attr *attr, unsigned long flag ) +{ + unsigned long flags; + + if ( slapi_attr_get_flags( attr, &flags ) != 0 ) + return 0; + return (flags & flag) ? 1 : 0; +} + +Slapi_Attr *slapi_attr_new( void ) +{ + Attribute *ad; + + ad = (Attribute *)slapi_ch_calloc( 1, sizeof(*ad) ); + + return ad; +} + +Slapi_Attr *slapi_attr_init( Slapi_Attr *a, const char *type ) +{ + const char *text; + AttributeDescription *ad = NULL; + + if( slap_str2ad( type, &ad, &text ) != LDAP_SUCCESS ) { + return NULL; + } + + a->a_desc = ad; + a->a_vals = NULL; + a->a_nvals = NULL; + a->a_next = NULL; + a->a_flags = 0; + + return a; +} + +void slapi_attr_free( Slapi_Attr **a ) +{ + attr_free( *a ); + *a = NULL; +} + +Slapi_Attr *slapi_attr_dup( const Slapi_Attr *attr ) +{ + return attr_dup( (Slapi_Attr *)attr ); +} + +int slapi_attr_add_value( Slapi_Attr *a, const Slapi_Value *v ) +{ + struct berval nval; + struct berval *nvalp; + int rc; + AttributeDescription *desc = a->a_desc; + + if ( desc->ad_type->sat_equality && + desc->ad_type->sat_equality->smr_normalize ) { + rc = (*desc->ad_type->sat_equality->smr_normalize)( + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + desc->ad_type->sat_syntax, + desc->ad_type->sat_equality, + (Slapi_Value *)v, &nval, NULL ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + nvalp = &nval; + } else { + nvalp = NULL; + } + + rc = attr_valadd( a, (Slapi_Value *)v, nvalp, 1 ); + + if ( nvalp != NULL ) { + slapi_ch_free_string( &nval.bv_val ); + } + + return rc; +} + +int slapi_attr_type2plugin( const char *type, void **pi ) +{ + *pi = NULL; + + return LDAP_OTHER; +} + +int slapi_attr_get_type( const Slapi_Attr *attr, char **type ) +{ + if ( attr == NULL ) { + return LDAP_PARAM_ERROR; + } + + *type = attr->a_desc->ad_cname.bv_val; + + return LDAP_SUCCESS; +} + +int slapi_attr_get_oid_copy( const Slapi_Attr *attr, char **oidp ) +{ + if ( attr == NULL ) { + return LDAP_PARAM_ERROR; + } + *oidp = attr->a_desc->ad_type->sat_oid; + + return LDAP_SUCCESS; +} + +int slapi_attr_value_cmp( const Slapi_Attr *a, const struct berval *v1, const struct berval *v2 ) +{ + MatchingRule *mr; + int ret; + int rc; + const char *text; + + mr = a->a_desc->ad_type->sat_equality; + rc = value_match( &ret, a->a_desc, mr, + SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, + (struct berval *)v1, (void *)v2, &text ); + if ( rc != LDAP_SUCCESS ) + return -1; + + return ( ret == 0 ) ? 0 : -1; +} + +int slapi_attr_value_find( const Slapi_Attr *a, struct berval *v ) +{ + int rc; + + if ( a ->a_vals == NULL ) { + return -1; + } + rc = attr_valfind( (Attribute *)a, SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, v, + NULL, NULL ); + return rc == 0 ? 0 : -1; +} + +int slapi_attr_type_cmp( const char *t1, const char *t2, int opt ) +{ + AttributeDescription *a1 = NULL; + AttributeDescription *a2 = NULL; + const char *text; + int ret; + + if ( slap_str2ad( t1, &a1, &text ) != LDAP_SUCCESS ) { + return -1; + } + + if ( slap_str2ad( t2, &a2, &text ) != LDAP_SUCCESS ) { + return 1; + } + +#define ad_base_cmp(l,r) (((l)->ad_type->sat_cname.bv_len < (r)->ad_type->sat_cname.bv_len) \ + ? -1 : (((l)->ad_type->sat_cname.bv_len > (r)->ad_type->sat_cname.bv_len) \ + ? 1 : strcasecmp((l)->ad_type->sat_cname.bv_val, (r)->ad_type->sat_cname.bv_val ))) + + switch ( opt ) { + case SLAPI_TYPE_CMP_EXACT: + ret = ad_cmp( a1, a2 ); + break; + case SLAPI_TYPE_CMP_BASE: + ret = ad_base_cmp( a1, a2 ); + break; + case SLAPI_TYPE_CMP_SUBTYPE: + ret = is_ad_subtype( a2, a2 ); + break; + default: + ret = -1; + break; + } + + return ret; +} + +int slapi_attr_types_equivalent( const char *t1, const char *t2 ) +{ + return ( slapi_attr_type_cmp( t1, t2, SLAPI_TYPE_CMP_EXACT ) == 0 ); +} + +int slapi_attr_first_value( Slapi_Attr *a, Slapi_Value **v ) +{ + return slapi_valueset_first_value( &a->a_vals, v ); +} + +int slapi_attr_next_value( Slapi_Attr *a, int hint, Slapi_Value **v ) +{ + return slapi_valueset_next_value( &a->a_vals, hint, v ); +} + +int slapi_attr_get_numvalues( const Slapi_Attr *a, int *numValues ) +{ + *numValues = slapi_valueset_count( &a->a_vals ); + + return 0; +} + +int slapi_attr_get_valueset( const Slapi_Attr *a, Slapi_ValueSet **vs ) +{ + *vs = &((Slapi_Attr *)a)->a_vals; + + return 0; +} + +int slapi_attr_get_bervals_copy( Slapi_Attr *a, struct berval ***vals ) +{ + return slapi_attr_get_values( a, vals ); +} + +char *slapi_attr_syntax_normalize( const char *s ) +{ + AttributeDescription *ad = NULL; + const char *text; + + if ( slap_str2ad( s, &ad, &text ) != LDAP_SUCCESS ) { + return NULL; + } + + return ad->ad_cname.bv_val; +} + +Slapi_Value *slapi_value_new( void ) +{ + struct berval *bv; + + bv = (struct berval *)slapi_ch_malloc( sizeof(*bv) ); + + return bv; +} + +Slapi_Value *slapi_value_new_berval(const struct berval *bval) +{ + return ber_dupbv( NULL, (struct berval *)bval ); +} + +Slapi_Value *slapi_value_new_value(const Slapi_Value *v) +{ + return slapi_value_new_berval( v ); +} + +Slapi_Value *slapi_value_new_string(const char *s) +{ + struct berval bv; + + bv.bv_val = (char *)s; + bv.bv_len = strlen( s ); + + return slapi_value_new_berval( &bv ); +} + +Slapi_Value *slapi_value_init(Slapi_Value *val) +{ + val->bv_val = NULL; + val->bv_len = 0; + + return val; +} + +Slapi_Value *slapi_value_init_berval(Slapi_Value *v, struct berval *bval) +{ + return ber_dupbv( v, bval ); +} + +Slapi_Value *slapi_value_init_string(Slapi_Value *v, const char *s) +{ + v->bv_val = slapi_ch_strdup( s ); + v->bv_len = strlen( s ); + + return v; +} + +Slapi_Value *slapi_value_dup(const Slapi_Value *v) +{ + return slapi_value_new_value( v ); +} + +void slapi_value_free(Slapi_Value **value) +{ + if ( value == NULL ) { + return; + } + + if ( (*value) != NULL ) { + slapi_ch_free( (void **)&(*value)->bv_val ); + slapi_ch_free( (void **)value ); + } +} + +const struct berval *slapi_value_get_berval( const Slapi_Value *value ) +{ + return value; +} + +Slapi_Value *slapi_value_set_berval( Slapi_Value *value, const struct berval *bval ) +{ + if ( value == NULL ) { + return NULL; + } + if ( value->bv_val != NULL ) { + slapi_ch_free( (void **)&value->bv_val ); + } + slapi_value_init_berval( value, (struct berval *)bval ); + + return value; +} + +Slapi_Value *slapi_value_set_value( Slapi_Value *value, const Slapi_Value *vfrom) +{ + if ( value == NULL ) { + return NULL; + } + return slapi_value_set_berval( value, vfrom ); +} + +Slapi_Value *slapi_value_set( Slapi_Value *value, void *val, unsigned long len) +{ + if ( value == NULL ) { + return NULL; + } + if ( value->bv_val != NULL ) { + slapi_ch_free( (void **)&value->bv_val ); + } + value->bv_val = slapi_ch_malloc( len ); + value->bv_len = len; + AC_MEMCPY( value->bv_val, val, len ); + + return value; +} + +int slapi_value_set_string(Slapi_Value *value, const char *strVal) +{ + if ( value == NULL ) { + return -1; + } + slapi_value_set( value, (void *)strVal, strlen( strVal ) ); + return 0; +} + +int slapi_value_set_int(Slapi_Value *value, int intVal) +{ + char buf[64]; + + snprintf( buf, sizeof( buf ), "%d", intVal ); + + return slapi_value_set_string( value, buf ); +} + +const char *slapi_value_get_string(const Slapi_Value *value) +{ + if ( value == NULL ) return NULL; + if ( value->bv_val == NULL ) return NULL; + if ( !checkBVString( value ) ) return NULL; + + return value->bv_val; +} + +int slapi_value_get_int(const Slapi_Value *value) +{ + if ( value == NULL ) return 0; + if ( value->bv_val == NULL ) return 0; + if ( !checkBVString( value ) ) return 0; + + return (int)strtol( value->bv_val, NULL, 10 ); +} + +unsigned int slapi_value_get_uint(const Slapi_Value *value) +{ + if ( value == NULL ) return 0; + if ( value->bv_val == NULL ) return 0; + if ( !checkBVString( value ) ) return 0; + + return (unsigned int)strtoul( value->bv_val, NULL, 10 ); +} + +long slapi_value_get_long(const Slapi_Value *value) +{ + if ( value == NULL ) return 0; + if ( value->bv_val == NULL ) return 0; + if ( !checkBVString( value ) ) return 0; + + return strtol( value->bv_val, NULL, 10 ); +} + +unsigned long slapi_value_get_ulong(const Slapi_Value *value) +{ + if ( value == NULL ) return 0; + if ( value->bv_val == NULL ) return 0; + if ( !checkBVString( value ) ) return 0; + + return strtoul( value->bv_val, NULL, 10 ); +} + +size_t slapi_value_get_length(const Slapi_Value *value) +{ + if ( value == NULL ) + return 0; + + return (size_t) value->bv_len; +} + +int slapi_value_compare(const Slapi_Attr *a, const Slapi_Value *v1, const Slapi_Value *v2) +{ + return slapi_attr_value_cmp( a, v1, v2 ); +} + +/* A ValueSet is a container for a BerVarray. */ +Slapi_ValueSet *slapi_valueset_new( void ) +{ + Slapi_ValueSet *vs; + + vs = (Slapi_ValueSet *)slapi_ch_malloc( sizeof( *vs ) ); + *vs = NULL; + + return vs; +} + +void slapi_valueset_free(Slapi_ValueSet *vs) +{ + if ( vs != NULL ) { + BerVarray vp = *vs; + + ber_bvarray_free( vp ); + vp = NULL; + + slapi_ch_free( (void **)&vp ); + } +} + +void slapi_valueset_init(Slapi_ValueSet *vs) +{ + if ( vs != NULL && *vs == NULL ) { + *vs = (Slapi_ValueSet)slapi_ch_calloc( 1, sizeof(struct berval) ); + (*vs)->bv_val = NULL; + (*vs)->bv_len = 0; + } +} + +void slapi_valueset_done(Slapi_ValueSet *vs) +{ + BerVarray vp; + + if ( vs == NULL ) + return; + + for ( vp = *vs; vp->bv_val != NULL; vp++ ) { + vp->bv_len = 0; + slapi_ch_free( (void **)&vp->bv_val ); + } + /* but don't free *vs or vs */ +} + +void slapi_valueset_add_value(Slapi_ValueSet *vs, const Slapi_Value *addval) +{ + struct berval bv; + + ber_dupbv( &bv, (Slapi_Value *)addval ); + ber_bvarray_add( vs, &bv ); +} + +int slapi_valueset_first_value( Slapi_ValueSet *vs, Slapi_Value **v ) +{ + return slapi_valueset_next_value( vs, 0, v ); +} + +int slapi_valueset_next_value( Slapi_ValueSet *vs, int index, Slapi_Value **v) +{ + int i; + BerVarray vp; + + if ( vs == NULL ) + return -1; + + vp = *vs; + + for ( i = 0; vp[i].bv_val != NULL; i++ ) { + if ( i == index ) { + *v = &vp[i]; + return index + 1; + } + } + + return -1; +} + +int slapi_valueset_count( const Slapi_ValueSet *vs ) +{ + int i; + BerVarray vp; + + if ( vs == NULL ) + return 0; + + vp = *vs; + + if ( vp == NULL ) + return 0; + + for ( i = 0; vp[i].bv_val != NULL; i++ ) + ; + + return i; + +} + +void slapi_valueset_set_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2) +{ + BerVarray vp; + + for ( vp = *vs2; vp->bv_val != NULL; vp++ ) { + slapi_valueset_add_value( vs1, vp ); + } +} + +int slapi_access_allowed( Slapi_PBlock *pb, Slapi_Entry *e, char *attr, + struct berval *val, int access ) +{ + int rc; + slap_access_t slap_access; + AttributeDescription *ad = NULL; + const char *text; + + rc = slap_str2ad( attr, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + /* + * Whilst the SLAPI access types are arranged as a bitmask, the + * documentation indicates that they are to be used separately. + */ + switch ( access & SLAPI_ACL_ALL ) { + case SLAPI_ACL_COMPARE: + slap_access = ACL_COMPARE; + break; + case SLAPI_ACL_SEARCH: + slap_access = ACL_SEARCH; + break; + case SLAPI_ACL_READ: + slap_access = ACL_READ; + break; + case SLAPI_ACL_WRITE: + slap_access = ACL_WRITE; + break; + case SLAPI_ACL_DELETE: + slap_access = ACL_WDEL; + break; + case SLAPI_ACL_ADD: + slap_access = ACL_WADD; + break; + case SLAPI_ACL_SELF: /* not documented */ + case SLAPI_ACL_PROXY: /* not documented */ + default: + return LDAP_INSUFFICIENT_ACCESS; + break; + } + + assert( pb->pb_op != NULL ); + + if ( access_allowed( pb->pb_op, e, ad, val, slap_access, NULL ) ) { + return LDAP_SUCCESS; + } + + return LDAP_INSUFFICIENT_ACCESS; +} + +int slapi_acl_check_mods(Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods, char **errbuf) +{ + int rc = LDAP_SUCCESS; + Modifications *ml; + + if ( pb == NULL || pb->pb_op == NULL ) + return LDAP_PARAM_ERROR; + + ml = slapi_int_ldapmods2modifications( pb->pb_op, mods ); + if ( ml == NULL ) { + return LDAP_OTHER; + } + + if ( rc == LDAP_SUCCESS ) { + rc = acl_check_modlist( pb->pb_op, e, ml ) ? LDAP_SUCCESS : LDAP_INSUFFICIENT_ACCESS; + } + + slap_mods_free( ml, 1 ); + + return rc; +} + +/* + * Synthesise an LDAPMod array from a Modifications list to pass + * to SLAPI. + */ +LDAPMod **slapi_int_modifications2ldapmods( Modifications *modlist ) +{ + Modifications *ml; + LDAPMod **mods, *modp; + int i, j; + + for( i = 0, ml = modlist; ml != NULL; i++, ml = ml->sml_next ) + ; + + mods = (LDAPMod **)slapi_ch_malloc( (i + 1) * sizeof(LDAPMod *) ); + + for( i = 0, ml = modlist; ml != NULL; ml = ml->sml_next ) { + mods[i] = (LDAPMod *)slapi_ch_malloc( sizeof(LDAPMod) ); + modp = mods[i]; + modp->mod_op = ml->sml_op | LDAP_MOD_BVALUES; + if ( BER_BVISNULL( &ml->sml_type ) ) { + /* may happen for internally generated mods */ + assert( ml->sml_desc != NULL ); + modp->mod_type = slapi_ch_strdup( ml->sml_desc->ad_cname.bv_val ); + } else { + modp->mod_type = slapi_ch_strdup( ml->sml_type.bv_val ); + } + + if ( ml->sml_values != NULL ) { + for( j = 0; ml->sml_values[j].bv_val != NULL; j++ ) + ; + modp->mod_bvalues = (struct berval **)slapi_ch_malloc( (j + 1) * + sizeof(struct berval *) ); + for( j = 0; ml->sml_values[j].bv_val != NULL; j++ ) { + modp->mod_bvalues[j] = (struct berval *)slapi_ch_malloc( + sizeof(struct berval) ); + ber_dupbv( modp->mod_bvalues[j], &ml->sml_values[j] ); + } + modp->mod_bvalues[j] = NULL; + } else { + modp->mod_bvalues = NULL; + } + i++; + } + + mods[i] = NULL; + + return mods; +} + +/* + * Convert a potentially modified array of LDAPMods back to a + * Modification list. Unfortunately the values need to be + * duplicated because slap_mods_check() will try to free them + * before prettying (and we can't easily get out of calling + * slap_mods_check() because we need normalized values). + */ +Modifications *slapi_int_ldapmods2modifications ( Operation *op, LDAPMod **mods ) +{ + Modifications *modlist = NULL, **modtail; + LDAPMod **modp; + char textbuf[SLAP_TEXT_BUFLEN]; + const char *text; + + if ( mods == NULL ) { + return NULL; + } + + modtail = &modlist; + + for ( modp = mods; *modp != NULL; modp++ ) { + Modifications *mod; + LDAPMod *lmod = *modp; + int i; + const char *text; + AttributeDescription *ad = NULL; + + if ( slap_str2ad( lmod->mod_type, &ad, &text ) != LDAP_SUCCESS ) { + continue; + } + + mod = (Modifications *) slapi_ch_malloc( sizeof(Modifications) ); + mod->sml_op = lmod->mod_op & ~(LDAP_MOD_BVALUES); + mod->sml_flags = 0; + mod->sml_type = ad->ad_cname; + mod->sml_desc = ad; + mod->sml_next = NULL; + + i = 0; + if ( lmod->mod_op & LDAP_MOD_BVALUES ) { + if ( lmod->mod_bvalues != NULL ) { + while ( lmod->mod_bvalues[i] != NULL ) + i++; + } + } else { + if ( lmod->mod_values != NULL ) { + while ( lmod->mod_values[i] != NULL ) + i++; + } + } + mod->sml_numvals = i; + + if ( i == 0 ) { + mod->sml_values = NULL; + } else { + mod->sml_values = (BerVarray) slapi_ch_malloc( (i + 1) * sizeof(struct berval) ); + + /* NB: This implicitly trusts a plugin to return valid modifications. */ + if ( lmod->mod_op & LDAP_MOD_BVALUES ) { + for ( i = 0; lmod->mod_bvalues[i] != NULL; i++ ) { + ber_dupbv( &mod->sml_values[i], lmod->mod_bvalues[i] ); + } + } else { + for ( i = 0; lmod->mod_values[i] != NULL; i++ ) { + mod->sml_values[i].bv_val = slapi_ch_strdup( lmod->mod_values[i] ); + mod->sml_values[i].bv_len = strlen( lmod->mod_values[i] ); + } + } + mod->sml_values[i].bv_val = NULL; + mod->sml_values[i].bv_len = 0; + } + mod->sml_nvalues = NULL; + + *modtail = mod; + modtail = &mod->sml_next; + } + + if ( slap_mods_check( op, modlist, &text, textbuf, sizeof( textbuf ), NULL ) != LDAP_SUCCESS ) { + slap_mods_free( modlist, 1 ); + modlist = NULL; + } + + return modlist; +} + +/* + * Sun ONE DS 5.x computed attribute support. Computed attributes + * allow for dynamically generated operational attributes, a very + * useful thing indeed. + */ + +/* + * For some reason Sun don't use the normal plugin mechanism + * registration path to register an "evaluator" function (an + * "evaluator" is responsible for adding computed attributes; + * the nomenclature is somewhat confusing). + * + * As such slapi_compute_add_evaluator() registers the + * function directly. + */ +int slapi_compute_add_evaluator(slapi_compute_callback_t function) +{ + Slapi_PBlock *pPlugin = NULL; + int rc; + int type = SLAPI_PLUGIN_OBJECT; + + pPlugin = slapi_pblock_new(); + if ( pPlugin == NULL ) { + rc = LDAP_NO_MEMORY; + goto done; + } + + rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_COMPUTE_EVALUATOR_FN, (void *)function ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + rc = slapi_int_register_plugin( frontendDB, pPlugin ); + if ( rc != 0 ) { + rc = LDAP_OTHER; + goto done; + } + +done: + if ( rc != LDAP_SUCCESS ) { + if ( pPlugin != NULL ) { + slapi_pblock_destroy( pPlugin ); + } + return -1; + } + + return 0; +} + +/* + * See notes above regarding slapi_compute_add_evaluator(). + */ +int slapi_compute_add_search_rewriter(slapi_search_rewrite_callback_t function) +{ + Slapi_PBlock *pPlugin = NULL; + int rc; + int type = SLAPI_PLUGIN_OBJECT; + + pPlugin = slapi_pblock_new(); + if ( pPlugin == NULL ) { + rc = LDAP_NO_MEMORY; + goto done; + } + + rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN, (void *)function ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + rc = slapi_int_register_plugin( frontendDB, pPlugin ); + if ( rc != 0 ) { + rc = LDAP_OTHER; + goto done; + } + +done: + if ( rc != LDAP_SUCCESS ) { + if ( pPlugin != NULL ) { + slapi_pblock_destroy( pPlugin ); + } + return -1; + } + + return 0; +} + +/* + * Call compute evaluators + */ +int compute_evaluator(computed_attr_context *c, char *type, Slapi_Entry *e, slapi_compute_output_t outputfn) +{ + int rc = 0; + slapi_compute_callback_t *pGetPlugin, *tmpPlugin; + + rc = slapi_int_get_plugins( frontendDB, SLAPI_PLUGIN_COMPUTE_EVALUATOR_FN, (SLAPI_FUNC **)&tmpPlugin ); + if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) { + /* Nothing to do; front-end should ignore. */ + return 0; + } + + for ( pGetPlugin = tmpPlugin; *pGetPlugin != NULL; pGetPlugin++ ) { + /* + * -1: no attribute matched requested type + * 0: one attribute matched + * >0: error happened + */ + rc = (*pGetPlugin)( c, type, e, outputfn ); + if ( rc > 0 ) { + break; + } + } + + slapi_ch_free( (void **)&tmpPlugin ); + + return rc; +} + +int +compute_rewrite_search_filter( Slapi_PBlock *pb ) +{ + if ( pb == NULL || pb->pb_op == NULL ) + return LDAP_PARAM_ERROR; + + return slapi_int_call_plugins( pb->pb_op->o_bd, SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN, pb ); +} + +/* + * New API to provide the plugin with access to the search + * pblock. Have informed Sun DS team. + */ +int +slapi_x_compute_get_pblock(computed_attr_context *c, Slapi_PBlock **pb) +{ + if ( c == NULL ) + return -1; + + if ( c->cac_pb == NULL ) + return -1; + + *pb = c->cac_pb; + + return 0; +} + +Slapi_Mutex *slapi_new_mutex( void ) +{ + Slapi_Mutex *m; + + m = (Slapi_Mutex *)slapi_ch_malloc( sizeof(*m) ); + if ( ldap_pvt_thread_mutex_init( &m->mutex ) != 0 ) { + slapi_ch_free( (void **)&m ); + return NULL; + } + + return m; +} + +void slapi_destroy_mutex( Slapi_Mutex *mutex ) +{ + if ( mutex != NULL ) { + ldap_pvt_thread_mutex_destroy( &mutex->mutex ); + slapi_ch_free( (void **)&mutex); + } +} + +void slapi_lock_mutex( Slapi_Mutex *mutex ) +{ + ldap_pvt_thread_mutex_lock( &mutex->mutex ); +} + +int slapi_unlock_mutex( Slapi_Mutex *mutex ) +{ + return ldap_pvt_thread_mutex_unlock( &mutex->mutex ); +} + +Slapi_CondVar *slapi_new_condvar( Slapi_Mutex *mutex ) +{ + Slapi_CondVar *cv; + + if ( mutex == NULL ) { + return NULL; + } + + cv = (Slapi_CondVar *)slapi_ch_malloc( sizeof(*cv) ); + if ( ldap_pvt_thread_cond_init( &cv->cond ) != 0 ) { + slapi_ch_free( (void **)&cv ); + return NULL; + } + + cv->mutex = mutex->mutex; + + return cv; +} + +void slapi_destroy_condvar( Slapi_CondVar *cvar ) +{ + if ( cvar != NULL ) { + ldap_pvt_thread_cond_destroy( &cvar->cond ); + slapi_ch_free( (void **)&cvar ); + } +} + +int slapi_wait_condvar( Slapi_CondVar *cvar, struct timeval *timeout ) +{ + if ( cvar == NULL ) { + return -1; + } + + return ldap_pvt_thread_cond_wait( &cvar->cond, &cvar->mutex ); +} + +int slapi_notify_condvar( Slapi_CondVar *cvar, int notify_all ) +{ + if ( cvar == NULL ) { + return -1; + } + + if ( notify_all ) { + return ldap_pvt_thread_cond_broadcast( &cvar->cond ); + } + + return ldap_pvt_thread_cond_signal( &cvar->cond ); +} + +int slapi_int_access_allowed( Operation *op, + Entry *entry, + AttributeDescription *desc, + struct berval *val, + slap_access_t access, + AccessControlState *state ) +{ + int rc, slap_access = 0; + slapi_acl_callback_t *pGetPlugin, *tmpPlugin; + Slapi_PBlock *pb; + + pb = SLAPI_OPERATION_PBLOCK( op ); + if ( pb == NULL ) { + /* internal operation */ + return 1; + } + + switch ( access ) { + case ACL_COMPARE: + slap_access |= SLAPI_ACL_COMPARE; + break; + case ACL_SEARCH: + slap_access |= SLAPI_ACL_SEARCH; + break; + case ACL_READ: + slap_access |= SLAPI_ACL_READ; + break; + case ACL_WRITE: + slap_access |= SLAPI_ACL_WRITE; + break; + case ACL_WDEL: + slap_access |= SLAPI_ACL_DELETE; + break; + case ACL_WADD: + slap_access |= SLAPI_ACL_ADD; + break; + default: + break; + } + + rc = slapi_int_get_plugins( frontendDB, SLAPI_PLUGIN_ACL_ALLOW_ACCESS, (SLAPI_FUNC **)&tmpPlugin ); + if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) { + /* nothing to do; allowed access */ + return 1; + } + + rc = 1; /* default allow policy */ + + for ( pGetPlugin = tmpPlugin; *pGetPlugin != NULL; pGetPlugin++ ) { + /* + * 0 access denied + * 1 access granted + */ + rc = (*pGetPlugin)( pb, entry, desc->ad_cname.bv_val, + val, slap_access, (void *)state ); + if ( rc == 0 ) { + break; + } + } + + slapi_ch_free( (void **)&tmpPlugin ); + + return rc; +} + +/* + * There is no documentation for this. + */ +int slapi_rdn2typeval( char *rdn, char **type, struct berval *bv ) +{ + LDAPRDN lrdn; + LDAPAVA *ava; + int rc; + char *p; + + *type = NULL; + + bv->bv_len = 0; + bv->bv_val = NULL; + + rc = ldap_str2rdn( rdn, &lrdn, &p, LDAP_DN_FORMAT_LDAPV3 ); + if ( rc != LDAP_SUCCESS ) { + return -1; + } + + if ( lrdn[1] != NULL ) { + return -1; /* not single valued */ + } + + ava = lrdn[0]; + + *type = slapi_ch_strdup( ava->la_attr.bv_val ); + ber_dupbv( bv, &ava->la_value ); + + ldap_rdnfree(lrdn); + + return 0; +} + +char *slapi_dn_plus_rdn( const char *dn, const char *rdn ) +{ + struct berval new_dn, parent_dn, newrdn; + + new_dn.bv_val = NULL; + + parent_dn.bv_val = (char *)dn; + parent_dn.bv_len = strlen( dn ); + + newrdn.bv_val = (char *)rdn; + newrdn.bv_len = strlen( rdn ); + + build_new_dn( &new_dn, &parent_dn, &newrdn, NULL ); + + return new_dn.bv_val; +} + +int slapi_entry_schema_check( Slapi_PBlock *pb, Slapi_Entry *e ) +{ + Backend *be_orig; + const char *text; + char textbuf[SLAP_TEXT_BUFLEN] = { '\0' }; + size_t textlen = sizeof textbuf; + int rc = LDAP_SUCCESS; + + PBLOCK_ASSERT_OP( pb, 0 ); + + be_orig = pb->pb_op->o_bd; + + pb->pb_op->o_bd = select_backend( &e->e_nname, 0 ); + if ( pb->pb_op->o_bd != NULL ) { + rc = entry_schema_check( pb->pb_op, e, NULL, 0, 0, NULL, + &text, textbuf, textlen ); + } + pb->pb_op->o_bd = be_orig; + + return ( rc == LDAP_SUCCESS ) ? 0 : 1; +} + +int slapi_entry_rdn_values_present( const Slapi_Entry *e ) +{ + LDAPDN dn; + int rc; + int i = 0, match = 0; + + rc = ldap_bv2dn( &((Entry *)e)->e_name, &dn, LDAP_DN_FORMAT_LDAPV3 ); + if ( rc != LDAP_SUCCESS ) { + return 0; + } + + if ( dn[0] != NULL ) { + LDAPRDN rdn = dn[0]; + + for ( i = 0; rdn[i] != NULL; i++ ) { + LDAPAVA *ava = &rdn[0][i]; + Slapi_Attr *a = NULL; + + if ( slapi_entry_attr_find( (Slapi_Entry *)e, ava->la_attr.bv_val, &a ) == 0 && + slapi_attr_value_find( a, &ava->la_value ) == 0 ) + match++; + } + } + + ldap_dnfree( dn ); + + return ( i == match ); +} + +int slapi_entry_add_rdn_values( Slapi_Entry *e ) +{ + LDAPDN dn; + int i, rc; + + rc = ldap_bv2dn( &e->e_name, &dn, LDAP_DN_FORMAT_LDAPV3 ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( dn[0] != NULL ) { + LDAPRDN rdn = dn[0]; + struct berval *vals[2]; + + for ( i = 0; rdn[i] != NULL; i++ ) { + LDAPAVA *ava = &rdn[0][i]; + Slapi_Attr *a = NULL; + + if ( slapi_entry_attr_find( e, ava->la_attr.bv_val, &a ) == 0 && + slapi_attr_value_find( a, &ava->la_value ) == 0 ) + continue; + + vals[0] = &ava->la_value; + vals[1] = NULL; + + slapi_entry_attr_merge( e, ava->la_attr.bv_val, vals ); + } + } + + ldap_dnfree( dn ); + + return LDAP_SUCCESS; +} + +const char *slapi_entry_get_uniqueid( const Slapi_Entry *e ) +{ + Attribute *attr; + + attr = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); + if ( attr == NULL ) { + return NULL; + } + + if ( attr->a_vals != NULL && attr->a_vals[0].bv_len != 0 ) { + return slapi_value_get_string( &attr->a_vals[0] ); + } + + return NULL; +} + +void slapi_entry_set_uniqueid( Slapi_Entry *e, char *uniqueid ) +{ + struct berval bv; + + attr_delete ( &e->e_attrs, slap_schema.si_ad_entryUUID ); + + bv.bv_val = uniqueid; + bv.bv_len = strlen( uniqueid ); + attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, &bv, NULL ); +} + +LDAP *slapi_ldap_init( char *ldaphost, int ldapport, int secure, int shared ) +{ + LDAP *ld; + char *url; + size_t size; + int rc; + + size = sizeof("ldap:///"); + if ( secure ) { + size++; + } + size += strlen( ldaphost ); + if ( ldapport != 0 ) { + size += 32; + } + + url = slapi_ch_malloc( size ); + + if ( ldapport != 0 ) { + rc = snprintf( url, size, "ldap%s://%s:%d/", ( secure ? "s" : "" ), ldaphost, ldapport ); + } else { + rc = snprintf( url, size, "ldap%s://%s/", ( secure ? "s" : "" ), ldaphost ); + } + + if ( rc > 0 && (size_t) rc < size ) { + rc = ldap_initialize( &ld, url ); + } else { + ld = NULL; + } + + slapi_ch_free_string( &url ); + + return ( rc == LDAP_SUCCESS ) ? ld : NULL; +} + +void slapi_ldap_unbind( LDAP *ld ) +{ + ldap_unbind_ext_s( ld, NULL, NULL ); +} + +int slapi_x_backend_get_flags( const Slapi_Backend *be, unsigned long *flags ) +{ + if ( be == NULL ) + return LDAP_PARAM_ERROR; + + *flags = SLAP_DBFLAGS(be); + + return LDAP_SUCCESS; +} + +int +slapi_int_count_controls( LDAPControl **ctrls ) +{ + size_t i; + + if ( ctrls == NULL ) + return 0; + + for ( i = 0; ctrls[i] != NULL; i++ ) + ; + + return i; +} + +int +slapi_op_abandoned( Slapi_PBlock *pb ) +{ + if ( pb->pb_op == NULL ) + return 0; + + return ( pb->pb_op->o_abandon ); +} + +char * +slapi_op_type_to_string(unsigned long type) +{ + char *str; + + switch (type) { + case SLAPI_OPERATION_BIND: + str = "bind"; + break; + case SLAPI_OPERATION_UNBIND: + str = "unbind"; + break; + case SLAPI_OPERATION_SEARCH: + str = "search"; + break; + case SLAPI_OPERATION_MODIFY: + str = "modify"; + break; + case SLAPI_OPERATION_ADD: + str = "add"; + break; + case SLAPI_OPERATION_DELETE: + str = "delete"; + break; + case SLAPI_OPERATION_MODDN: + str = "modrdn"; + break; + case SLAPI_OPERATION_COMPARE: + str = "compare"; + break; + case SLAPI_OPERATION_ABANDON: + str = "abandon"; + break; + case SLAPI_OPERATION_EXTENDED: + str = "extended"; + break; + default: + str = "unknown operation type"; + break; + } + return str; +} + +unsigned long +slapi_op_get_type(Slapi_Operation * op) +{ + unsigned long type; + + switch ( op->o_tag ) { + case LDAP_REQ_BIND: + type = SLAPI_OPERATION_BIND; + break; + case LDAP_REQ_UNBIND: + type = SLAPI_OPERATION_UNBIND; + break; + case LDAP_REQ_SEARCH: + type = SLAPI_OPERATION_SEARCH; + break; + case LDAP_REQ_MODIFY: + type = SLAPI_OPERATION_MODIFY; + break; + case LDAP_REQ_ADD: + type = SLAPI_OPERATION_ADD; + break; + case LDAP_REQ_DELETE: + type = SLAPI_OPERATION_DELETE; + break; + case LDAP_REQ_MODRDN: + type = SLAPI_OPERATION_MODDN; + break; + case LDAP_REQ_COMPARE: + type = SLAPI_OPERATION_COMPARE; + break; + case LDAP_REQ_ABANDON: + type = SLAPI_OPERATION_ABANDON; + break; + case LDAP_REQ_EXTENDED: + type = SLAPI_OPERATION_EXTENDED; + break; + default: + type = SLAPI_OPERATION_NONE; + break; + } + return type; +} + +void slapi_be_set_readonly( Slapi_Backend *be, int readonly ) +{ + if ( be == NULL ) + return; + + if ( readonly ) + be->be_restrictops |= SLAP_RESTRICT_OP_WRITES; + else + be->be_restrictops &= ~(SLAP_RESTRICT_OP_WRITES); +} + +int slapi_be_get_readonly( Slapi_Backend *be ) +{ + if ( be == NULL ) + return 0; + + return ( (be->be_restrictops & SLAP_RESTRICT_OP_WRITES) == SLAP_RESTRICT_OP_WRITES ); +} + +const char *slapi_x_be_get_updatedn( Slapi_Backend *be ) +{ + if ( be == NULL ) + return NULL; + + return be->be_update_ndn.bv_val; +} + +Slapi_Backend *slapi_be_select( const Slapi_DN *sdn ) +{ + Slapi_Backend *be; + + slapi_sdn_get_ndn( sdn ); + + be = select_backend( (struct berval *)&sdn->ndn, 0 ); + + return be; +} + +#if 0 +void +slapi_operation_set_flag(Slapi_Operation *op, unsigned long flag) +{ +} + +void +slapi_operation_clear_flag(Slapi_Operation *op, unsigned long flag) +{ +} + +int +slapi_operation_is_flag_set(Slapi_Operation *op, unsigned long flag) +{ +} +#endif + +#endif /* LDAP_SLAPI */ + diff --git a/servers/slapd/slapindex.c b/servers/slapd/slapindex.c new file mode 100644 index 0000000..0f22387 --- /dev/null +++ b/servers/slapd/slapindex.c @@ -0,0 +1,110 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * Portions Copyright 1998-2003 Kurt D. Zeilenga. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Kurt Zeilenga for inclusion + * in OpenLDAP Software. + */ + +#include "portable.h" + +#include <stdio.h> + +#include <ac/stdlib.h> + +#include <ac/ctype.h> +#include <ac/string.h> +#include <ac/socket.h> +#include <ac/unistd.h> + +#include "slapcommon.h" + +int +slapindex( int argc, char **argv ) +{ + ID id; + int rc = EXIT_SUCCESS; + const char *progname = "slapindex"; + AttributeDescription *ad, **adv = NULL; + + slap_tool_init( progname, SLAPINDEX, argc, argv ); + + if( !be->be_entry_open || + !be->be_entry_close || + !( be->be_entry_first || be->be_entry_first_x ) || + !be->be_entry_next || + !be->be_entry_reindex ) + { + fprintf( stderr, "%s: database doesn't support necessary operations.\n", + progname ); + exit( EXIT_FAILURE ); + } + + argc -= optind; + if ( argc > 0 ) { + const char *text; + int i; + + argv = &argv[optind]; + adv = (AttributeDescription **)argv; + + for (i = 0; i < argc; i++ ) { + ad = NULL; + rc = slap_str2ad( argv[i], &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, "slap_str2ad(%s) failed %d (%s)\n", + argv[i], rc, ldap_err2string( rc )); + exit( EXIT_FAILURE ); + } + adv[i] = ad; + } + } + + if( be->be_entry_open( be, 0 ) != 0 ) { + fprintf( stderr, "%s: could not open database.\n", + progname ); + exit( EXIT_FAILURE ); + } + + if ( be->be_entry_first ) { + id = be->be_entry_first( be ); + + } else { + assert( be->be_entry_first_x != NULL ); + id = be->be_entry_first_x( be, NULL, LDAP_SCOPE_DEFAULT, NULL ); + } + + for ( ; id != NOID; id = be->be_entry_next( be ) ) { + int rtn; + + if( verbose ) { + printf("indexing id=%08lx\n", (long) id ); + } + + rtn = be->be_entry_reindex( be, id, adv ); + + if( rtn != LDAP_SUCCESS ) { + rc = EXIT_FAILURE; + if( continuemode ) continue; + break; + } + } + + (void) be->be_entry_close( be ); + + if ( slap_tool_destroy()) + rc = EXIT_FAILURE; + return( rc ); +} |